트렌드 컨셉 Top 3 (Step 1)
사전 분석된 릴스 레퍼런스에서 캠페인에 맞는 트렌드 컨셉 3개를 자동 선정합니다.
트렌드 컨셉 Top 3
캠페인 카테고리에 맞는 레퍼런스 릴스와 GENERAL 레퍼런스를 후보로 모아, 제품 정보와 비교해 적합한 트렌드 컨셉 3개를 자동 선정합니다. 결과는 V4 와 동일한 GuidelineDocument 세션에 저장되며 status 가 CONCEPTS_GENERATED 로 전이됩니다.
HTTP 요청
POST /ai/guideline/v5/{collabNo}/concepts
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
V4 컨셉 생성과 동일한 ConceptsRequest 를 사용합니다.
{
"conceptText": "",
"fileUrls": ["https://..."],
"referenceLinks": ["https://..."],
"regenerate": false,
"regenerationPrompt": "",
"requestId": "3f2b8c1e-6a4d-4e2f-9b1a-7c5d2e8f0a11"
}| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
conceptText | String | 아니오 | 컨셉 자유 입력 텍스트 |
fileUrls | Array<String> | 아니오 | 참고 이미지/PDF 등 GCS URL |
referenceLinks | Array<String> | 아니오 | 참고 링크 |
regenerate | Boolean | 아니오 | true 면 기존 세션 컨셉을 previous_concepts 로 Python 에 전달해 중복을 피함 |
regenerationPrompt | String | 아니오 | 다시 생성 시 사용자가 입력한 추가 방향 지시 |
requestId | String | 아니오 | 이 생성 요청의 ID(UUID 권장). 클라이언트가 만들어 보내면 세션 조회 의 generationRequestId 와 대조해 내 요청이 끝났는지 판정할 수 있습니다. 생략하면 서버가 생성합니다 |
부가 처리
- 호출 시 캠페인 이미지 분석(
analyzeImagesByCollabNo)을 먼저 수행합니다. 실패해도 컨셉 생성은 계속 진행됩니다. - 캠페인의 실제 카테고리를
category_code로 Python 에 전달합니다. - Python 응답 전체(
generation_id,recommendation_id,rank,trend_context등 포함)를 세션concepts에 저장하고geminiFileIds/pdfMetadata/referenceMetadata도 함께 저장합니다. 세션expiresAt은 현재 + 48시간(172,800초)으로 갱신됩니다. - 요청 시작 시 세션에
generationRequestId·generationStatus=RUNNING·generationStartedAt을 기록하고, 끝나면DONE(Python 실패 시FAILED+generationError)으로 바꿉니다. 세션 문서가 아직 없는 첫 생성은 끝날 때 문서가 만들어집니다. - 클라이언트 응답에는 화면에 필요한 필드만 내려갑니다(아래 참고). 내부 식별자는 서버가 보관했다가 generate 호출 시 Python 에 그대로 전달합니다.
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "트렌드 컨셉 생성 완료",
"data": {
"concepts": [
{
"name": "컨셉 이름",
"description": "컨셉 상세 설명 텍스트",
"one_liner": "컨셉을 한 줄로 요약",
"trend_name": "선정된 트렌드 주제",
"why_selected": "이 캠페인에 이 트렌드를 고른 이유",
"application_points": [
"가이드에 적용할 방식 1",
"가이드에 적용할 방식 2"
],
"reference_reels": [
{
"source_url": "https://www.instagram.com/reel/abc123/",
"observed_pattern": "반복 관찰된 연출 패턴"
}
]
},
{ "...": "..." },
{ "...": "..." }
],
"requestId": "3f2b8c1e-6a4d-4e2f-9b1a-7c5d2e8f0a11",
"superseded": false
}
}data 필드 설명
| 필드 | 타입 | 설명 |
|---|---|---|
concepts | Array<ConceptItem> | 트렌드 컨셉 3개 (항상 3개, 자동 선정 순위대로 정렬) |
requestId | String | 이 요청의 ID (요청에 보낸 값, 없었으면 서버가 만든 값) |
superseded | Boolean | true 면 이 요청이 도는 사이 더 최근 요청이 시작되어 결과가 세션에 반영되지 않았음. 이때 concepts 는 화면에 쓰지 말고 세션을 다시 조회할 것 |
ConceptItem 구조
| 필드 | 타입 | 설명 |
|---|---|---|
name | String | 컨셉 이름 |
description | String | 컨셉 설명 |
one_liner | String | 한 줄 요약 |
trend_name | String | 선정된 트렌드 주제명 (trend_context.trend_name). 원본에 값이 없으면 null |
why_selected | String | 이 트렌드를 선정한 이유 |
application_points | Array<String> | 가이드 적용 방식. 없으면 빈 배열 |
reference_reels | Array<ReferenceReel> | 근거 릴스. 없으면 빈 배열 |
ReferenceReel 구조
| 필드 | 타입 | 설명 |
|---|---|---|
source_url | String | 원본 릴스 URL (DB 원본으로 강제 교정된 값) |
observed_pattern | String | 반복 관찰된 연출 패턴 |
응답 배열의 인덱스가 곧 전체 가이드라인 생성 의 conceptIndex 입니다. 순위(rank), generation_id, recommendation_id, trend_context 전문, selection_signals, evidence_reel_count, tradeoff, gemini_file_ids, pdf_metadata 는 응답에 포함되지 않고 서버 세션에만 보관됩니다.
이 축약은 trend_context 를 가진 컨셉(= V5 로 생성된 컨셉)에만 적용됩니다. trend_context 가 없는 기존 V4 컨셉은 저장된 형태 그대로 반환됩니다.
동시 요청 처리 (마지막 요청 우선)
컨셉 생성은 동기 호출이라 사용자가 화면을 떠나도 서버에서 끝까지 진행됩니다. 그 사이 새 요청이 들어오면 마지막으로 시작된 요청의 결과만 세션에 반영하고, 먼저 시작된 요청의 결과는 버립니다(응답 superseded: true).
- 완료 판정은 컨셉 내용 비교 대신 세션 조회 의
generationRequestId가 내requestId이고generationStatus가DONE인지로 합니다. generationRequestId가 내 값과 다르면 더 최근 요청이 있는 것이므로 내 요청은 무효입니다.- 결과 반영은 컨셉 관련 필드만 부분 갱신합니다. 생성 도중 저장된 가이드라인 본문(
selectedConcept/data)을 되돌리지 않습니다.
숫자 점수는 사용하지 않습니다. 모델이 명시된 선정 기준(제품 적합성 · 근거 반복성 · 자연스러운 제품 통합 · 촬영 가능성)으로 후보를 비교해 1~3위와 근거를 반환합니다.
에러
IllegalArgumentException: 캠페인을 찾을 수 없음 ("캠페인을 찾을 수 없습니다. collabNo=...")- Python 생성 실패: 세션
generationStatus를FAILED로 기록한 뒤 기존과 같은 오류 응답을 반환합니다(해당 요청이 여전히 최신일 때만 기록)