限制 PPT 視覺 QA 投影片抽查
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s

This commit is contained in:
OoO
2026-05-19 09:48:00 +08:00
parent c0ba5e876a
commit cb0446e85f
3 changed files with 21 additions and 3 deletions

View File

@@ -315,6 +315,7 @@ RAG_EMBED_NORMALIZE=true
PPT_VISION_ENABLED=true
PPT_VISION_MODEL=minicpm-v:latest
PPT_VISION_TIMEOUT=120
PPT_VISION_MAX_SLIDES=1
PPT_AUTO_GENERATION_ENABLED=true
PPT_AUTO_REPORT_TYPES=all
PPT_AUTO_DEFAULT_CATEGORY=美妝保養

View File

@@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.232"
SYSTEM_VERSION = "V10.233"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -36,6 +36,7 @@ logger = logging.getLogger(__name__)
# ─────────────────────────────────────────────────────────────────────────────
PPT_VISION_MODEL = os.getenv('PPT_VISION_MODEL', 'minicpm-v:latest')
PPT_VISION_TIMEOUT = int(os.getenv('PPT_VISION_TIMEOUT', '120'))
PPT_VISION_MAX_SLIDES = int(os.getenv('PPT_VISION_MAX_SLIDES', '1'))
PPT_VISION_IMAGE_MAX_EDGE = int(os.getenv('PPT_VISION_IMAGE_MAX_EDGE', '1280'))
PPT_VISION_IMAGE_QUALITY = int(os.getenv('PPT_VISION_IMAGE_QUALITY', '82'))
_AUDIT_LOCK = threading.Lock()
@@ -182,6 +183,16 @@ def _is_recent_active_audit_run(run: Dict[str, Any] | None) -> bool:
return age is None or age < _ACTIVE_AUDIT_TTL_SECONDS
def _is_vision_infra_error(error: str | None) -> bool:
text = (error or '').lower()
return any(marker in text for marker in (
'all 3 hosts failed',
'connection',
'ollama vision failed',
'timeout',
))
def _public_audit_run_payload(run: Dict[str, Any] | None) -> Dict[str, Any] | None:
if not run:
return None
@@ -316,7 +327,7 @@ class PPTVisionService:
with open(image_path, 'rb') as f:
return base64.b64encode(f.read()).decode('ascii')
def check_ppt_file(self, pptx_path: str, max_slides: int = 5) -> Dict[str, Any]:
def check_ppt_file(self, pptx_path: str, max_slides: int | None = None) -> Dict[str, Any]:
"""檢查整份 .pptx — Phase 26 整合到 PPT 生成流程。
流程:
@@ -338,6 +349,7 @@ class PPTVisionService:
import subprocess
import tempfile
max_slides = max(1, int(max_slides or PPT_VISION_MAX_SLIDES))
result = {
'success': False, 'slides_checked': 0, 'total_issues': 0,
'issues_by_slide': [], 'error': None,
@@ -424,11 +436,16 @@ class PPTVisionService:
result['total_issues'] += len(vr.issues_found)
result['issues_by_slide'].append((idx + 1, vr.issues_found))
else:
slide_errors.append(f"slide {idx + 1}: {vr.error or 'vision model failed'}")
message = f"slide {idx + 1}: {vr.error or 'vision model failed'}"
slide_errors.append(message)
if _is_vision_infra_error(vr.error):
break
except Exception as exc:
message = f"slide {idx + 1}: {type(exc).__name__}: {str(exc)[:160]}"
slide_errors.append(message)
logger.warning(f"[PPTVision] slide {idx+1} check failed: {exc}")
if _is_vision_infra_error(message):
break
result['success'] = result['slides_checked'] > 0
if not result['success'] and slide_errors: