diff --git a/app/services/grok/processors/chat_processors.py b/app/services/grok/processors/chat_processors.py index 8f7c153..000e09b 100644 --- a/app/services/grok/processors/chat_processors.py +++ b/app/services/grok/processors/chat_processors.py @@ -166,13 +166,20 @@ class StreamProcessor(BaseProcessor): img_id = parts[-2] if len(parts) >= 2 else "image" if self.image_format == "base64": - dl_service = self._get_dl() - base64_data = await dl_service.to_base64( - url, self.token, "image" - ) - if base64_data: - yield self._sse(f"![{img_id}]({base64_data})\n") - else: + try: + dl_service = self._get_dl() + base64_data = await dl_service.to_base64( + url, self.token, "image" + ) + if base64_data: + yield self._sse(f"![{img_id}]({base64_data})\n") + else: + final_url = await self.process_url(url, "image") + yield self._sse(f"![{img_id}]({final_url})\n") + except Exception as e: + logger.warning( + f"Failed to convert image to base64, falling back to URL: {e}" + ) final_url = await self.process_url(url, "image") yield self._sse(f"![{img_id}]({final_url})\n") else: @@ -287,13 +294,20 @@ class CollectProcessor(BaseProcessor): img_id = parts[-2] if len(parts) >= 2 else "image" if self.image_format == "base64": - dl_service = self._get_dl() - base64_data = await dl_service.to_base64( - url, self.token, "image" - ) - if base64_data: - content += f"![{img_id}]({base64_data})\n" - else: + try: + dl_service = self._get_dl() + base64_data = await dl_service.to_base64( + url, self.token, "image" + ) + if base64_data: + content += f"![{img_id}]({base64_data})\n" + else: + final_url = await self.process_url(url, "image") + content += f"![{img_id}]({final_url})\n" + except Exception as e: + logger.warning( + f"Failed to convert image to base64, falling back to URL: {e}" + ) final_url = await self.process_url(url, "image") content += f"![{img_id}]({final_url})\n" else: diff --git a/app/services/grok/processors/image_processors.py b/app/services/grok/processors/image_processors.py index 2dac0bd..8f78ac3 100644 --- a/app/services/grok/processors/image_processors.py +++ b/app/services/grok/processors/image_processors.py @@ -93,16 +93,24 @@ class ImageStreamProcessor(BaseProcessor): if processed: final_images.append(processed) continue - dl_service = self._get_dl() - base64_data = await dl_service.to_base64( - url, self.token, "image" - ) - if base64_data: - if "," in base64_data: - b64 = base64_data.split(",", 1)[1] - else: - b64 = base64_data - final_images.append(b64) + try: + dl_service = self._get_dl() + base64_data = await dl_service.to_base64( + url, self.token, "image" + ) + if base64_data: + if "," in base64_data: + b64 = base64_data.split(",", 1)[1] + else: + b64 = base64_data + final_images.append(b64) + except Exception as e: + logger.warning( + f"Failed to convert image to base64, falling back to URL: {e}" + ) + processed = await self.process_url(url, "image") + if processed: + final_images.append(processed) continue for index, b64 in enumerate(final_images): @@ -198,16 +206,24 @@ class ImageCollectProcessor(BaseProcessor): if processed: images.append(processed) continue - dl_service = self._get_dl() - base64_data = await dl_service.to_base64( - url, self.token, "image" - ) - if base64_data: - if "," in base64_data: - b64 = base64_data.split(",", 1)[1] - else: - b64 = base64_data - images.append(b64) + try: + dl_service = self._get_dl() + base64_data = await dl_service.to_base64( + url, self.token, "image" + ) + if base64_data: + if "," in base64_data: + b64 = base64_data.split(",", 1)[1] + else: + b64 = base64_data + images.append(b64) + except Exception as e: + logger.warning( + f"Failed to convert image to base64, falling back to URL: {e}" + ) + processed = await self.process_url(url, "image") + if processed: + images.append(processed) except asyncio.CancelledError: logger.debug("Image collect cancelled by client") diff --git a/app/services/grok/services/assets.py b/app/services/grok/services/assets.py index d19ab4a..3c14a0d 100644 --- a/app/services/grok/services/assets.py +++ b/app/services/grok/services/assets.py @@ -242,8 +242,22 @@ class BaseService: def to_b64(file_path: Path, mime_type: str) -> str: """文件转 base64 data URI""" try: + if not file_path.exists(): + logger.warning(f"File not found for base64 conversion: {file_path}") + raise AppException( + f"File not found: {file_path}", code="file_not_found" + ) + + if not file_path.is_file(): + logger.warning(f"Path is not a file: {file_path}") + raise AppException( + f"Invalid file path: {file_path}", code="invalid_file_path" + ) + b64_data = base64.b64encode(file_path.read_bytes()).decode() return f"data:{mime_type};base64,{b64_data}" + except AppException: + raise except Exception as e: logger.error(f"File to base64 failed: {file_path} - {e}") raise AppException( @@ -581,20 +595,27 @@ class DownloadService(BaseService): self, file_path: str, token: str, media_type: str = "image" ) -> str: """下载并转 base64""" - cache_path, mime = await self.download(file_path, token, media_type) - if not cache_path or not cache_path.exists(): - raise AppException("Download failed: invalid path") + try: + cache_path, mime = await self.download(file_path, token, media_type) + if not cache_path or not cache_path.exists(): + logger.warning(f"Download failed for {file_path}: invalid path") + raise AppException( + "Download failed: invalid path", code="download_failed" + ) - data_uri = self.to_b64(cache_path, mime) + data_uri = self.to_b64(cache_path, mime) - # 删除临时文件 - if data_uri: - try: - cache_path.unlink() - except Exception: - pass + # 删除临时文件 + if data_uri: + try: + cache_path.unlink() + except Exception as e: + logger.debug(f"Failed to cleanup temp file {cache_path}: {e}") - return data_uri + return data_uri + except Exception as e: + logger.error(f"Failed to convert {file_path} to base64: {e}") + raise def get_stats(self, media_type: str = "image") -> Dict[str, Any]: """获取缓存统计""" diff --git a/app/services/grok/services/media.py b/app/services/grok/services/media.py index e3f4917..37e186f 100644 --- a/app/services/grok/services/media.py +++ b/app/services/grok/services/media.py @@ -152,7 +152,7 @@ class VideoService: } mode_flag = mode_map.get(preset, "--mode=custom") - return { + payload = { "temporary": True, "modelName": "grok-3", "message": f"{prompt} {mode_flag}", @@ -163,16 +163,20 @@ class VideoService: "modelConfigOverride": { "modelMap": { "videoGenModelConfig": { - "parentPostId": post_id, "aspectRatio": aspect_ratio, - "videoLength": video_length, + "parentPostId": post_id, "resolutionName": resolution_name, + "videoLength": video_length } } }, }, } + logger.debug(f"Video generation payload: {payload}") + + return payload + async def _generate_internal( self, token: str,