# ChatGPT API 에러 처리 개선 계획서 ## 1. 현황 분석 ### 1.1 `generate_structured_output` 사용처 | 파일 | 용도 | DB 상태 업데이트 | 응답 상태 변수 | |------|------|-----------------|----------------| | `app/lyric/worker/lyric_task.py` | 가사 생성 | ✅ "failed" 저장 | - (백그라운드) | | `app/home/api/routers/v1/home.py` | 크롤링 마케팅 분석 | ❌ 없음 | ❌ 없음 | ### 1.2 응답 스키마 상태 변수 현황 | 스키마 | 위치 | 상태 변수 | 조치 | |--------|------|----------|------| | `CrawlingResponse` | home_schema.py:158 | ❌ 없음 | `status` 추가 | | `GenerateLyricResponse` | lyric.py:72 | ✅ `success: bool` | `False`로 설정 | | `LyricStatusResponse` | lyric.py:105 | ✅ `status: str` | `"failed"` 설정 | | `LyricDetailResponse` | lyric.py:128 | ✅ `status: str` | `"failed"` 설정 | --- ## 2. 개선 목표 1. **DB 상태 업데이트**: 에러 발생 시 DB에 `status = "failed"` 저장 2. **클라이언트 응답**: 기존 상태 변수가 있으면 `"failed"` 설정, 없으면 변수 추가 후 설정 --- ## 3. 상세 작업 계획 ### 3.1 lyric_task.py - `ChatGPTResponseError` 명시적 처리 **파일**: `app/lyric/worker/lyric_task.py` **현재 코드 (Line 138-141)**: ```python except Exception as e: elapsed = (time.perf_counter() - task_start) * 1000 logger.error(f"[generate_lyric_background] EXCEPTION - task_id: {task_id}, error: {e} ({elapsed:.1f}ms)", exc_info=True) await _update_lyric_status(task_id, "failed", f"Error: {str(e)}") ``` **변경 코드**: ```python from app.utils.chatgpt_prompt import ChatgptService, ChatGPTResponseError # ... 기존 코드 ... except ChatGPTResponseError as e: elapsed = (time.perf_counter() - task_start) * 1000 logger.error( f"[generate_lyric_background] ChatGPT ERROR - task_id: {task_id}, " f"status: {e.status}, code: {e.error_code} ({elapsed:.1f}ms)" ) await _update_lyric_status(task_id, "failed", f"ChatGPT Error: {e.error_message}") except SQLAlchemyError as e: # ... 기존 코드 유지 ... except Exception as e: # ... 기존 코드 유지 ... ``` **결과**: DB `lyric.status` = `"failed"`, `lyric.lyric_result` = 에러 메시지 --- ### 3.2 home.py - CrawlingResponse에 status 추가 **파일**: `app/home/schemas/home_schema.py` **현재 코드 (Line 158-168)**: ```python class CrawlingResponse(BaseModel): """크롤링 응답 스키마""" image_list: Optional[list[str]] = Field(None, description="이미지 URL 목록") image_count: int = Field(..., description="이미지 개수") processed_info: Optional[ProcessedInfo] = Field(None, ...) marketing_analysis: Optional[MarketingAnalysis] = Field(None, ...) ``` **변경 코드**: ```python class CrawlingResponse(BaseModel): """크롤링 응답 스키마""" status: str = Field( default="completed", description="처리 상태 (completed, failed)" ) image_list: Optional[list[str]] = Field(None, description="이미지 URL 목록") image_count: int = Field(..., description="이미지 개수") processed_info: Optional[ProcessedInfo] = Field(None, ...) marketing_analysis: Optional[MarketingAnalysis] = Field(None, ...) ``` --- ### 3.3 home.py - 크롤링 엔드포인트 에러 처리 **파일**: `app/home/api/routers/v1/home.py` **현재 코드 (Line 296-303)**: ```python except Exception as e: step3_elapsed = (time.perf_counter() - step3_start) * 1000 logger.error(...) marketing_analysis = None ``` **변경 코드**: ```python from app.utils.chatgpt_prompt import ChatgptService, ChatGPTResponseError # ... 기존 코드 ... except ChatGPTResponseError as e: step3_elapsed = (time.perf_counter() - step3_start) * 1000 logger.error( f"[crawling] Step 3 FAILED - ChatGPT Error: {e.status}, {e.error_code} ({step3_elapsed:.1f}ms)" ) marketing_analysis = None gpt_status = "failed" except Exception as e: step3_elapsed = (time.perf_counter() - step3_start) * 1000 logger.error(...) marketing_analysis = None gpt_status = "failed" # 응답 반환 부분 수정 return { "status": gpt_status if 'gpt_status' in locals() else "completed", "image_list": scraper.image_link_list, "image_count": len(scraper.image_link_list) if scraper.image_link_list else 0, "processed_info": processed_info, "marketing_analysis": marketing_analysis, } ``` --- ## 4. 파일 변경 요약 | 파일 | 변경 내용 | |------|----------| | `app/lyric/worker/lyric_task.py` | `ChatGPTResponseError` import 및 명시적 처리 추가 | | `app/home/schemas/home_schema.py` | `CrawlingResponse`에 `status` 필드 추가 | | `app/home/api/routers/v1/home.py` | `ChatGPTResponseError` 처리, 응답에 `status` 포함 | --- ## 5. 변경 후 동작 ### 5.1 lyric_task.py (가사 생성) | 상황 | DB status | DB lyric_result | |------|-----------|-----------------| | 성공 | `"completed"` | 생성된 가사 | | ChatGPT 에러 | `"failed"` | `"ChatGPT Error: {message}"` | | DB 에러 | `"failed"` | `"Database Error: {message}"` | | 기타 에러 | `"failed"` | `"Error: {message}"` | ### 5.2 home.py (크롤링) | 상황 | 응답 status | marketing_analysis | |------|------------|-------------------| | 성공 | `"completed"` | 분석 결과 | | ChatGPT 에러 | `"failed"` | `null` | | 기타 에러 | `"failed"` | `null` | --- ## 6. 구현 순서 1. `app/home/schemas/home_schema.py` - `CrawlingResponse`에 `status` 필드 추가 2. `app/lyric/worker/lyric_task.py` - `ChatGPTResponseError` 명시적 처리 3. `app/home/api/routers/v1/home.py` - 에러 처리 및 응답 `status` 설정