직접입력시 업종추가

feature-imageMatch
김성경 2026-07-03 15:59:52 +09:00
parent 46449a7a3f
commit 4d8462651a
4 changed files with 36 additions and 10 deletions

View File

@ -421,6 +421,7 @@ async def _crawling_logic(
## 요청 필드
- **customer_name**: 업체명 / 브랜드명 (필수)
- **address**: 도로명 또는 지번 주소 (필수)
- **category**: 업종/카테고리 자유 입력 (선택, : 펜션, 카페). 비우면 업체명 기반 AI 분류
## 반환 정보
- **processed_info**: 가공된 장소 정보 (customer_name, region, detail_region_info)
@ -445,9 +446,9 @@ async def manual_marketing(
# Step 2: GPT API 호출 → 마케팅 분석 결과 생성
# place_id 없이 업체명+주소만으로 분석 (크롤링 없이 직접 입력된 경우)
chatgpt_service = ChatgptService()
# 요청에 industry가 있으면 사용, 없으면 업체명 기반 AI 분류
industry = request_body.industry or await _resolve_industry(
"", request_body.store_name
# 크롤링 경로와 동일하게 category를 우선 사용하고, 없으면 업체명 기반 AI 분류
industry = await _resolve_industry(
request_body.category, request_body.store_name
)
processed_info.industry = industry
input_marketing_data = {

View File

@ -260,13 +260,14 @@ class ManualMarketingRequest(BaseModel):
"example": {
"store_name": "스테이 머뭄",
"address": "전북특별자치도 군산시 절골길 18",
"category": "펜션",
}
}
)
store_name: str = Field(..., description="업체명 / 브랜드명")
address: str = Field(..., description="도로명 또는 지번 주소")
industry: str = Field(default="", description="종 분류 (stay|restaurant|cafe|salon|clinic|fitness|academy|attraction). 비우면 업체명 기반 AI 분류")
category: str = Field(default="", description="체 업종/카테고리 자유 입력 (예: 펜션, 카페). 크롤링 경로와 동일하게 AI가 8개 industry enum으로 자동 분류하는 데 사용. 비우면 업체명 기반 AI 분류")
class ErrorResponse(BaseModel):

View File

@ -1,6 +1,6 @@
import json
import re
from pydantic import BaseModel
from pydantic import BaseModel, ValidationError
from typing import List, Optional
from openai import AsyncOpenAI
@ -131,11 +131,23 @@ class ChatgptService:
})
last_error = None
for attempt in range(self.max_retries + 1):
response = await self.client.beta.chat.completions.parse(
model=model,
messages=[{"role": "user", "content": content}],
response_format=output_format
)
try:
response = await self.client.beta.chat.completions.parse(
model=model,
messages=[{"role": "user", "content": content}],
response_format=output_format
)
except (ValidationError, json.JSONDecodeError) as e:
# 모델이 스키마에 맞지 않는 JSON을 반환한 경우 (예: trailing characters).
# 확률적 출력 문제일 수 있으므로 재시도 대상에 포함한다.
logger.warning(
f"[ChatgptService({self.model_type})] Structured output parse failed "
f"(attempt {attempt + 1}/{self.max_retries + 1}): {e}"
)
last_error = ChatGPTResponseError("parse_error", type(e).__name__, str(e))
if attempt < self.max_retries:
logger.info(f"[ChatgptService({self.model_type})] Retrying request...")
continue
# Response 디버그 로깅
logger.debug(f"[ChatgptService({self.model_type})] attempt: {attempt}")
logger.debug(f"[ChatgptService({self.model_type})] Response ID: {response.id}")

View File

@ -0,0 +1,12 @@
-- ============================================================
-- Migration: marketing 테이블에 image_match 컬럼 추가
-- Date: 2026-07-03
-- Description: 이미지 슬롯 배정 결과물 저장
-- - lyric 생성 사전 단계(get_image_tags_by_task_id → template_matching_taged_image)에서
-- 산출된 슬롯별 이미지 배정 결과를 저장
-- - 영상 생성 시점에는 저장된 결과를 읽어 음악 URL/주소만 보완하여 재사용
-- ============================================================
ALTER TABLE marketing
ADD COLUMN image_match JSON NULL
COMMENT '이미지 슬롯 배정 결과물' AFTER subtitle;