POST /ai/campaign/image-sufficiency
상세페이지 이미지 충분성 판정
상세페이지 이미지 충분성 판정
캠페인 썸네일·상세페이지 이미지가 가이드라인 생성에 필요한 정보를 충분히 담고 있는지 판정합니다.
프론트는 판정 결과가 INSUFFICIENT 일 때 추가 자료 요청 팝업을 띄웁니다.
Spring 은 Python 판정 API(POST /report/campaign/check-image-sufficiency)를 동기 호출하며,
응답을 그대로 전달합니다. 기존 이미지 분석(POST /ai/report/campaign/{collabNo}/analyze-images)과는
독립적으로 동작하고, 분석 결과나 캐시(product_details)를 변경하지 않습니다.
| 항목 | 값 |
|---|---|
| 메서드 | POST |
| 경로 | /ai/campaign/image-sufficiency (별칭 /campaign/image-sufficiency) |
| 인증 | 필요 (ROLE_BUSINESS / ROLE_ADMIN) |
| Content-Type | application/json |
Gemini 다중 이미지 판정이라 응답까지 수십 초가 걸릴 수 있습니다. 팝업이 필요한 화면 흐름에서 호출하고 응답 대기 중 로딩 상태를 표시하세요. 비동기 이미지 분석 이벤트에는 연결하지 않습니다.
요청
POST /ai/campaign/image-sufficiency HTTP/1.1
Host: api.glowb.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"campaignNo": 2309,
"productName": "제주 호텔 숙박권",
"imageUrls": [
"https://cdn.example.com/thumbnail.jpg",
"https://cdn.example.com/detail.jpg"
]
}curl -X POST "https://api.glowb.com/ai/campaign/image-sufficiency" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"campaignNo": 2309,
"productName": "제주 호텔 숙박권",
"imageUrls": ["https://cdn.example.com/thumbnail.jpg"]
}'const response = await fetch('/ai/campaign/image-sufficiency', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignNo,
productName,
imageUrls
})
});
const { data } = await response.json();
if (data.status === 'INSUFFICIENT') {
showAdditionalMaterialPopup(); // 다국어 고정 안내문
} else if (data.status === 'FAILED') {
showRetryToast();
}Request Body
Prop
Type
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "이미지 충분성 판정이 완료되었습니다.",
"data": {
"status": "INSUFFICIENT",
"product_image_match": false,
"detected_product_name": "",
"satisfied_criteria": [],
"missing_criteria": [
"PRODUCT_IDENTITY",
"CORE_BENEFIT",
"CONCRETE_TARGET",
"USAGE_CONDITIONS",
"DIFFERENTIATION"
],
"criteria": {
"PRODUCT_IDENTITY": {
"satisfied": false,
"evidence": [],
"reason": "상품이나 서비스명을 확인할 수 없음"
}
},
"reason": "상품 식별과 핵심 혜택을 이미지에서 확인할 수 없습니다.",
"guidance": "브랜드·서비스명과 핵심 혜택이 표시된 이미지를 추가해 주세요.",
"requested_image_count": 2,
"selected_image_count": 2,
"analyzed_image_count": 2,
"prompt_version": "product-page-sufficiency-v1"
}
}실제 criteria 에는 5개 조건이 모두 포함됩니다.
판정 상태 (data.status)
| 값 | 의미 | 프론트 처리 |
|---|---|---|
SUFFICIENT | 충분성 조건 충족 | 기존 생성 흐름 계속 진행 |
INSUFFICIENT | 판정은 완료됐으나 제품 불일치 또는 조건 미충족 | 고정 안내문 팝업 표시 (시스템 오류 아님) |
FAILED | 이미지 다운로드 또는 Gemini 판정 실패, Python 호출 실패 | 재시도 안내 표시 |
프론트는 status 만 사용합니다. guidance, missing_criteria, reason 은 운영 확인·디버깅용이며
사용자 화면에 직접 표시하지 않습니다. 팝업 문구는 프론트 다국어 리소스에서 관리합니다.
상세페이지 정보가 부족합니다.
제품명과 핵심 혜택을 확인할 수 있는 이미지를 추가해 주세요.판정 조건
| 코드 | 설명 |
|---|---|
PRODUCT_IDENTITY | 상품·서비스명과 유형 (필수) |
CORE_BENEFIT | 핵심 혜택·효능 (필수) |
CONCRETE_TARGET | 구체적인 대상·구성 |
USAGE_CONDITIONS | 이용법·이용 조건 |
DIFFERENTIATION | 차별점 |
SUFFICIENT 가 되려면 아래를 모두 만족해야 합니다. 이미지 수 자체는 통과 조건이 아닙니다.
- 제품명과 이미지 대상이 일치 (
product_image_match) PRODUCT_IDENTITY,CORE_BENEFIT필수 충족- 5개 조건 중 3개 이상 충족
- 각 충족 조건에 이미지 근거(
evidence)가 1개 이상 존재
응답 필드
Prop
Type
에러 응답
| 상태 코드 | 설명 |
|---|---|
400 | productName 누락 (VALIDATION_ERROR) / 판정할 이미지 없음 (REQ_001) |
401 | 인증 실패 |
403 | ROLE_BUSINESS · ROLE_ADMIN 권한 부족 |
404 | campaignNo 로 캠페인을 찾을 수 없음 (CAMPAIGN_NOT_FOUND) |
Python 호출 실패(타임아웃·5xx·422·빈 응답)는 에러로 내리지 않고 data.status 를 FAILED 로 채워
HTTP 200 으로 응답합니다. 프론트가 INSUFFICIENT 와 시스템 오류를 상태 값만으로 구분할 수 있게 하기 위함입니다.
이미지 처리
- 최대 40개 URL 사용, 초과 시 첫·마지막을 포함해 균등 선택 (Python 담당)
- S3·CloudFront 및 일반 HTTP(S) URL 지원
- 공개 또는 서명된 GCP HTTPS URL 지원
gs://와 인증이 필요한 비공개 GCS URL 은 미지원- AVIF 는 실행 환경에 따라 분석에서 제외될 수 있음
로그 · 저장 정책
- Spring 은
campaignNo, 상태, 누락 조건, 이미지 수, 소요 시간, 프롬프트 버전을 애플리케이션 로그로 남깁니다. SUFFICIENT·INSUFFICIENT는INFO, 판정 실패는WARN, Python 호출 실패는ERROR입니다.- 이미지 URL, Gemini 원문 응답,
guidance는 로그에 남기지 않습니다. - 판정 결과는 Spring · Python 어느 쪽에서도 DB 에 저장하지 않습니다.