diff --git a/src/api/routes.py b/src/api/routes.py index 71865cf..569ab5e 100644 --- a/src/api/routes.py +++ b/src/api/routes.py @@ -93,8 +93,8 @@ def _guess_mime_type(uri: str, fallback: str) -> str: async def retrieve_image_data(url: str) -> Optional[bytes]: """Read image bytes from local /tmp cache or remote URL.""" + file_cache = getattr(generation_handler, "file_cache", None) try: - file_cache = getattr(generation_handler, "file_cache", None) if "/tmp/" in url and file_cache: path = urlparse(url).path filename = path.split("/tmp/")[-1] @@ -107,15 +107,30 @@ async def retrieve_image_data(url: str) -> Optional[bytes]: except Exception as exc: debug_logger.log_warning(f"[CONTEXT] 本地缓存读取失败: {str(exc)}") + proxy_url = None + try: + if file_cache and hasattr(file_cache, "_resolve_download_proxy"): + proxy_url = await file_cache._resolve_download_proxy("image") + except Exception as exc: + debug_logger.log_warning(f"[CONTEXT] 图片下载代理解析失败: {str(exc)}") + try: async with AsyncSession() as session: response = await session.get( url, - timeout=30, - impersonate="chrome110", + timeout=60, + proxies={"http": proxy_url, "https": proxy_url} if proxy_url else None, + headers={ + "Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Accept-Encoding": "gzip, deflate, br", + "Connection": "keep-alive", + "Referer": "https://labs.google/", + }, + impersonate="chrome120", verify=False, ) - if response.status_code == 200: + if response.status_code == 200 and response.content: return response.content debug_logger.log_warning( f"[CONTEXT] 图片下载失败,状态码: {response.status_code}" @@ -418,7 +433,8 @@ async def _build_image_parts_from_uri(uri: str) -> List[Dict[str, Any]]: "mimeType": _guess_mime_type(uri, "image/png"), "fileUri": uri, } - } + }, + {"text": uri}, ] diff --git a/static/manage.html b/static/manage.html index 5df9bd7..4b622ea 100644 --- a/static/manage.html +++ b/static/manage.html @@ -833,7 +833,7 @@ getLogOperationLabel=l=>{const operation=String(l&&l.operation||'').trim();if(operation==='generate_image')return'图片';if(operation==='generate_video')return'视频';return''}, formatLogOutcome=l=>{const statusCode=Number(l&&l.status_code);if(statusCode===200){const operationLabel=getLogOperationLabel(l);return operationLabel?`${operationLabel}结果已返回`:'已返回结果'}if(statusCode===102)return'处理中';const errorSummary=extractLogErrorSummary(l);if(errorSummary)return truncateLogText(errorSummary,96);return statusCode>=400?'请求失败':'-'}, formatLogOutcomeClass=l=>{if((l.status_code||0)>=400)return'text-red-600';if(l.status_code===200)return'text-green-700';if(l.status_code===102)return'text-amber-700';return'text-muted-foreground'}, - startLogsAutoRefresh=()=>{if(window.logsAutoRefreshTimer)return;window.logsAutoRefreshTimer=setInterval(()=>{const panel=$('panelLogs');if(panel&&!panel.classList.contains('hidden'))loadLogs({silent:true})},5000)}, + startLogsAutoRefresh=()=>{stopLogsAutoRefresh()}, stopLogsAutoRefresh=()=>{if(window.logsAutoRefreshTimer){clearInterval(window.logsAutoRefreshTimer);window.logsAutoRefreshTimer=null}}, loadLogs=async(opts={})=>{const silent=!!opts.silent;try{const r=await apiRequest('/api/logs?limit=100');if(!r)return;const logs=await r.json();window.allLogs=logs;window.logDetailCache=window.logDetailCache||Object.create(null);window.logListMeta=Object.create(null);logs.forEach(l=>window.logListMeta[l.id]={updated_at:l.updated_at,created_at:l.created_at,status_code:l.status_code,progress:l.progress,status_text:l.status_text,error_summary:l.error_summary||''});Object.keys(window.logDetailCache).forEach(key=>{const meta=window.logListMeta[key];const cached=window.logDetailCache[key];if(!meta||!cached||cached.updated_at!==meta.updated_at)delete window.logDetailCache[key]});const tb=$('logsTableBody');if(!logs.length){tb.innerHTML='
${label}: data URL(长度 ${String(url).length})
`; + const normalizedUrl=normalizeLogMediaUrl(url); + if(/^data:/i.test(String(normalizedUrl))){ + return `${label}: data URL(长度 ${String(normalizedUrl).length})
`; } - const safeUrl=escapeLogHtml(url); + const safeUrl=escapeLogHtml(normalizedUrl); return `${label}: ${safeUrl}
`; } @@ -1001,10 +1017,18 @@ function renderMediaPreview(label,url,withUrl=true){ if(!url) return ''; - const mediaType=isVideoUrl(url)?'video':(isImageUrl(url)?'image':''); - const mediaKey=mediaType?cacheLogMediaUrl(url):''; + const previewUrl=normalizeLogMediaUrl(url); + const mediaType=isVideoUrl(previewUrl)?'video':(isImageUrl(previewUrl)?'image':''); + const mediaKey=mediaType?cacheLogMediaUrl(previewUrl):''; const previewTrigger=mediaType?``:''; - return `${escapeLogHtml(label)}
${withUrl?renderLogLink('URL',url):''}${previewTrigger}${escapeLogHtml(label)}
${withUrl?renderLogLink('URL',previewUrl):''}${previewTrigger}${escapeLogHtml(mediaLabel)}预览加载失败,请直接打开链接查看。
${renderLogLink('URL',mediaUrl)}放大分辨率: ${escapeLogHtml(upResolution)}
`; if(upPreviewUrl){ - assetsHtml+=renderMediaPreview(`${upResolution}结果`,upPreviewUrl,false); + assetsHtml+=renderMediaPreview(`${upResolution}结果`,upPreviewUrl,!/^data:/i.test(String(upPreviewUrl||''))); } if(up.base64){ const preview=String(up.base64).length>600?`${String(up.base64).slice(0,600)}...`:String(up.base64);