자막생성 재시도 로직 추가

feature-ADO2
김성경 2026-05-27 15:44:44 +09:00
parent 5f3e8ec341
commit 73e5da3f08
3 changed files with 87 additions and 51 deletions

View File

@ -212,6 +212,7 @@ class SubtitleStatusResponse(BaseModel):
Status Values: Status Values:
- pending: 자막 생성 진행 (재시도 필요) - pending: 자막 생성 진행 (재시도 필요)
- completed: 자막 생성 완료 (/video/generate 호출 가능) - completed: 자막 생성 완료 (/video/generate 호출 가능)
- failed: 자막 생성 실패 (/lyric/generate 재호출 필요)
""" """
model_config = ConfigDict( model_config = ConfigDict(
@ -233,12 +234,20 @@ class SubtitleStatusResponse(BaseModel):
"message": "자막 생성이 완료되었습니다.", "message": "자막 생성이 완료되었습니다.",
}, },
}, },
{
"summary": "실패",
"value": {
"task_id": "0694b716-dbff-7219-8000-d08cb5fce431",
"status": "failed",
"message": "자막 생성에 실패했습니다. 다시 시도해주세요.",
},
},
] ]
} }
) )
task_id: str = Field(..., description="작업 고유 식별자") task_id: str = Field(..., description="작업 고유 식별자")
status: Literal["pending", "completed"] = Field(..., description="자막 생성 상태") status: Literal["pending", "completed", "failed"] = Field(..., description="자막 생성 상태")
message: str = Field(..., description="상태 메시지") message: str = Field(..., description="상태 메시지")

View File

@ -158,9 +158,12 @@ async def generate_lyric_background(
async def generate_subtitle_background( async def generate_subtitle_background(
orientation: str, orientation: str,
task_id: str task_id: str,
max_retries: int = 3,
) -> None: ) -> None:
logger.info(f"[generate_subtitle_background] START - task_id: {task_id}, orientation: {orientation}") logger.info(f"[generate_subtitle_background] START - task_id: {task_id}, orientation: {orientation}")
for attempt in range(1, max_retries + 1):
try: try:
creatomate_service = CreatomateService(orientation=orientation) creatomate_service = CreatomateService(orientation=orientation)
template = await creatomate_service.get_one_template_data(creatomate_service.template_id) template = await creatomate_service.get_one_template_data(creatomate_service.template_id)
@ -207,10 +210,15 @@ async def generate_subtitle_background(
marketing_intelligence.subtitle = subtitle_modifications marketing_intelligence.subtitle = subtitle_modifications
await session.commit() await session.commit()
logger.info(f"[generate_subtitle_background] DONE - task_id: {task_id}") logger.info(f"[generate_subtitle_background] DONE - task_id: {task_id} (attempt {attempt}/{max_retries})")
return
except Exception as e: except Exception as e:
logger.error( logger.error(
f"[generate_subtitle_background] FAILED - task_id: {task_id}, error: {e}", f"[generate_subtitle_background] FAILED (attempt {attempt}/{max_retries}) - task_id: {task_id}, error: {e}",
exc_info=True, exc_info=True,
) )
if attempt < max_retries:
logger.info(f"[generate_subtitle_background] 재시도 중... ({attempt + 1}/{max_retries}) - task_id: {task_id}")
logger.error(f"[generate_subtitle_background] 모든 재시도 실패 - task_id: {task_id}")

View File

@ -10,11 +10,20 @@ from app.utils.prompts.chatgpt_prompt import ChatgptService
from app.utils.prompts.schemas import * from app.utils.prompts.schemas import *
from app.utils.prompts.prompts import * from app.utils.prompts.prompts import *
logger = get_logger("subtitle")
class SubtitleContentsGenerator(): class SubtitleContentsGenerator():
def __init__(self): def __init__(self):
self.chatgpt_service = ChatgptService() self.chatgpt_service = ChatgptService(timeout=60.0)
async def generate_subtitle_contents(self, marketing_intelligence : dict[str, Any], pitching_label_list : list[Any], customer_name : str, detail_region_info : str) -> SubtitlePromptOutput: async def generate_subtitle_contents(self, marketing_intelligence : dict[str, Any], pitching_label_list : list[Any], customer_name : str, detail_region_info : str) -> SubtitlePromptOutput:
start = time.perf_counter()
logger.info(
f"[SubtitleContentsGenerator] START - customer: {customer_name}, "
f"pitching_count: {len(pitching_label_list)}, "
f"labels: {pitching_label_list}"
)
dynamic_subtitle_prompt = create_dynamic_subtitle_prompt(len(pitching_label_list)) dynamic_subtitle_prompt = create_dynamic_subtitle_prompt(len(pitching_label_list))
pitching_label_string = "\n".join(pitching_label_list) pitching_label_string = "\n".join(pitching_label_list)
marketing_intel_string = json.dumps(marketing_intelligence, ensure_ascii=False) marketing_intel_string = json.dumps(marketing_intelligence, ensure_ascii=False)
@ -24,7 +33,17 @@ class SubtitleContentsGenerator():
"customer_name" : customer_name, "customer_name" : customer_name,
"detail_region_info" : detail_region_info, "detail_region_info" : detail_region_info,
} }
logger.info(
f"[SubtitleContentsGenerator] GPT 호출 시작 - model: {dynamic_subtitle_prompt.prompt_model}"
)
output_data = await self.chatgpt_service.generate_structured_output(dynamic_subtitle_prompt, input_data) output_data = await self.chatgpt_service.generate_structured_output(dynamic_subtitle_prompt, input_data)
elapsed = (time.perf_counter() - start) * 1000
logger.info(
f"[SubtitleContentsGenerator] DONE - 소요시간: {elapsed:.0f}ms, "
f"결과: {[r.pitching_tag for r in output_data.pitching_results]}"
)
return output_data return output_data