Skip to content

Commit d37f8fa

Browse files
authored
Merge pull request #1296 from joker1point/fix/openai-image-invalid-content
fix(material): 200 响应 body 非图片时跳过关键词而非中断任务
2 parents 3ade9fb + aac5c76 commit d37f8fa

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

app/services/material.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,17 @@ def generate_images_openai(
14131413
)
14141414
return []
14151415

1416-
image_path, width, height = _save_openai_image_file(image_bytes, save_dir)
1416+
try:
1417+
image_path, width, height = _save_openai_image_file(image_bytes, save_dir)
1418+
except Exception as e:
1419+
# 兼容层可能返回 200 但 body 不是图片(如伪装成 JSON 的 HTML 错误页、
1420+
# 网关的降级提示页)。图片无法解码属于"该次生成已失败",按素材源
1421+
# 约定返回空列表让上层跳过该关键词继续,而不是让异常中断整个任务。
1422+
logger.error(
1423+
"openai image response is not a decodable image, skipping term: "
1424+
f"term={search_term!r}, error={type(e).__name__}, detail={e}"
1425+
)
1426+
return []
14171427
item = MaterialInfo()
14181428
item.provider = "openai_image"
14191429
item.url = image_path

test/services/test_material_openai_image.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,43 @@ def test_generate_images_openai_with_url_response(self):
152152
"https://cdn.example.com/generated/abc.png?sig=1",
153153
)
154154

155+
def test_generate_images_openai_skips_b64_json_with_invalid_image(self):
156+
"""
157+
兼容层返回 200 但 body 不是可解码图片(如伪装成 JSON 的 HTML 错误页)
158+
时,必须按素材源约定返回空列表让上层跳过该关键词,而不是让解码
159+
异常中断整个任务。
160+
"""
161+
fake_content = b"<html><body>gateway degraded</body></html>"
162+
response = _image_response(
163+
{"data": [{"b64_json": base64.b64encode(fake_content).decode("ascii")}]}
164+
)
165+
166+
with patch("app.services.material.requests.post", return_value=response):
167+
results = material.generate_images_openai(
168+
"sunrise over mountains", minimum_duration=5, save_dir=self.save_dir
169+
)
170+
171+
self.assertEqual(results, [])
172+
self.assertEqual(os.listdir(self.save_dir), [])
173+
174+
def test_generate_images_openai_skips_url_download_with_invalid_content(self):
175+
"""临时 URL 下载到 200 的非图片内容时同样走跳过路径。"""
176+
response = _image_response(
177+
{"data": [{"url": "https://cdn.example.com/generated/abc.png?sig=1"}]}
178+
)
179+
download = _download_response(b"\x89PNG\r\n\x1a\nnot-really-a-png")
180+
181+
with (
182+
patch("app.services.material.requests.post", return_value=response),
183+
patch("app.services.material.requests.get", return_value=download),
184+
):
185+
results = material.generate_images_openai(
186+
"city at night", minimum_duration=3, save_dir=self.save_dir
187+
)
188+
189+
self.assertEqual(results, [])
190+
self.assertEqual(os.listdir(self.save_dir), [])
191+
155192
# ------------------------------------------------------------------
156193
# 退避重试与 key 轮换
157194
# ------------------------------------------------------------------

0 commit comments

Comments
 (0)