feat: integrate quality-gated draw flow with online dispatch transfer
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled

This commit is contained in:
2026-03-03 14:10:00 +08:00
parent 5e9590030d
commit 484f1f6be4
4 changed files with 223 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import asyncio
import base64
import logging
import os
import re
@@ -191,10 +192,20 @@ def _extract_line(text: str, key: str) -> str:
def _parse_result(text: str) -> dict[str, Any]:
intent = _extract_line(text, "诉求类型")
if not intent:
intent = _extract_line(text, "类型")
can_do = _extract_line(text, "可做").lower()
business_related = _extract_line(text, "业务相关").lower()
complexity = _extract_line(text, "复杂度").lower()
price_text = _extract_line(text, "建议报价")
if not price_text:
price_text = _extract_line(text, "建议价格")
gemini_prompt = _extract_line(text, "提示词")
aspect_ratio = _extract_line(text, "比例")
risk = _extract_line(text, "风险").lower()
note = _extract_line(text, "说明")
if not note:
note = _extract_line(text, "备注")
if intent not in {"找图", "高清修复", "其他"}:
intent = "其他"
@@ -202,6 +213,12 @@ def _parse_result(text: str) -> dict[str, Any]:
can_do = "partial"
if complexity not in {"simple", "normal", "complex", "hard"}:
complexity = "normal"
if business_related not in {"yes", "no"}:
business_related = "yes"
if aspect_ratio not in {"1:1", "9:16", "16:9", "3:4", "4:3", "3:2", "2:3", "5:4", "4:5"}:
aspect_ratio = "1:1"
if risk not in {"none", "low", "high"}:
risk = "none"
price = 0
m = re.search(r"\d+", price_text or "")
@@ -211,8 +228,12 @@ def _parse_result(text: str) -> dict[str, Any]:
return {
"intent_type": intent,
"can_do": can_do,
"business_related": business_related,
"complexity": complexity,
"price_suggest": price,
"gemini_prompt": gemini_prompt or "",
"aspect_ratio": aspect_ratio,
"risk": risk,
"note": note or "已看图",
}
@@ -263,3 +284,61 @@ async def analyze_image_for_quote(image_url: str, customer_text: str = "", goods
logger.error("[识图报价] 调用失败: %s", e)
return {"ok": False, "error": str(e)}
def _image_file_to_data_url(path: str) -> str:
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
return f"data:image/jpeg;base64,{b64}"
async def evaluate_generated_image(
original_image_url: str,
generated_image_path: str,
requirement: str = "",
) -> dict[str, Any]:
"""
生成后质量评估:不通过则建议直接退出,不发送给客户。
"""
if not OPENAI_API_KEY:
return {"ok": False, "pass": True, "reason": "no_api_key_skip"}
if not os.path.exists(generated_image_path):
return {"ok": False, "pass": False, "reason": "generated_file_missing"}
client = AsyncOpenAI(base_url=OPENAI_BASE_URL, api_key=OPENAI_API_KEY)
review_prompt = (
"你是印花/印刷交付质检。请对比原图和生成图,判断是否可发给客户。\n"
"重点看主体是否跑偏、细节是否糊、是否明显AI味、是否不适合印刷。\n"
"只输出两行:\n"
"评估: <pass|fail>\n"
"原因: <20字内>\n"
f"客户要求: {requirement or ''}"
)
try:
gen_url = _image_file_to_data_url(generated_image_path)
resp = await asyncio.wait_for(
client.chat.completions.create(
model=VISION_MODEL,
temperature=0.1,
messages=[
{"role": "system", "content": "你是严格的图像交付质检员。"},
{
"role": "user",
"content": [
{"type": "text", "text": review_prompt},
{"type": "image_url", "image_url": {"url": original_image_url}},
{"type": "image_url", "image_url": {"url": gen_url}},
],
},
],
),
timeout=30,
)
text = str((resp.choices[0].message.content if resp and resp.choices else "") or "").strip()
flag = _extract_line(text, "评估").lower()
reason = _extract_line(text, "原因") or _clip(text, 40)
passed = flag == "pass"
logger.info("[作图评估] result=%s reason=%s", "pass" if passed else "fail", reason)
return {"ok": True, "pass": passed, "reason": reason, "raw": text}
except Exception as e:
logger.error("[作图评估] 调用失败: %s", e)
return {"ok": False, "pass": False, "reason": str(e)}