#967 implement media_relay endpoint - fix WeChat bot image relay
media_relay was a stub (empty function body). Now implements actual image/video streaming relay from S3 to WeChat clients, with domain whitelist and httpx streaming. Fixes WeChat bot image generation responses not rendered.
This commit is contained in:
1 parent
75be24ce9c
commit
54b444b651
1 file changed
+47
@@ -155,6 +155,17 @@ _MEDIA_RELAY_ALLOWED = ("agnes-ai.com", "agnes-ai.space", "qihuyun.com")
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Media relay client (trust_env=False to bypass proxy for image fetches)
|
||||||
|
_media_client = None
|
||||||
|
def _get_media_client():
|
||||||
|
global _media_client
|
||||||
|
if _media_client is None:
|
||||||
|
_media_client = httpx.Client(timeout=30.0, follow_redirects=True, trust_env=False)
|
||||||
|
return _media_client
|
||||||
|
|
||||||
|
|
||||||
@router.get("/media/relay")
|
@router.get("/media/relay")
|
||||||
|
|
||||||
|
|
||||||
@@ -197,6 +208,42 @@ async def media_relay(url: str = Query(...)):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import urllib.parse as _up
|
||||||
|
import httpx
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
|
|
||||||
|
host = (_up.urlparse(url).hostname or "").lower()
|
||||||
|
# 白名单域名检查
|
||||||
|
allowed = ("siliconflow.cn", "s3.siliconflow.cn", "aliyuncs.com", "tencentcos.cn",
|
||||||
|
"qpic.cn", "alicdn.com", "api.openai.com", "myqcloud.com")
|
||||||
|
if not any(a in host for a in allowed):
|
||||||
|
raise HTTPException(status_code=400, detail="unsupported media host")
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = _get_media_client()
|
||||||
|
resp = client.get(url, timeout=30.0, follow_redirects=True)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
raise HTTPException(status_code=502, detail=f"upstream returned {resp.status_code}")
|
||||||
|
ct = resp.headers.get("content-type", "application/octet-stream")
|
||||||
|
cl = resp.headers.get("content-length")
|
||||||
|
headers = {}
|
||||||
|
if ct:
|
||||||
|
headers["content-type"] = ct
|
||||||
|
if cl:
|
||||||
|
headers["content-length"] = cl
|
||||||
|
headers["cache-control"] = "public, max-age=3600"
|
||||||
|
return StreamingResponse(
|
||||||
|
resp.iter_bytes(chunk_size=65536),
|
||||||
|
status_code=200,
|
||||||
|
headers=headers,
|
||||||
|
media_type=ct
|
||||||
|
)
|
||||||
|
except httpx.TimeoutException:
|
||||||
|
raise HTTPException(status_code=504, detail="upstream timeout")
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=502, detail=f"relay error: {str(e)[:200]}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user