o2o-castad-backend/error_plan.md

179 lines
5.8 KiB
Markdown

# 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` 설정