# InsuRo 통합 AI 큐 시스템 — 모든 AI 기능 대기열 통합

## 작업 레벨: Lv.3

## 프로젝트 시스템 3문서
- DevSystem: `/home/jay/workspace/memory/plans/anu-guide-system/plan.md`

## 프로젝트
- InsuRo: `/home/jay/projects/InsuRo`
- 서버: `/home/jay/projects/InsuRo/server`

## 배경
모든 AI 기능이 아누 서버(claude CLI subprocess)로 집중됨. 현재 콘텐츠 생성만 큐 시스템(`generation_queue.py`, Semaphore 10건) 적용. 나머지 AI 기능은 큐 없이 직접 subprocess 호출 → 동시 요청 과부하 위험.

## 수정 사항

### 1. 통합 AI 큐 모듈 (server/ai_queue.py 신규)

기존 `generation_queue.py`를 확장한 범용 큐:

```python
import asyncio
from enum import IntEnum
from dataclasses import dataclass, field
from datetime import datetime
import uuid

class AIPriority(IntEnum):
    URGENT = 1    # 사용자 실시간 대기 (콘텐츠 생성, 증권 분석)
    NORMAL = 2    # 일반 요청 (주제 추천, 고객 분석, 상담 평가)
    BACKGROUND = 3 # 백그라운드 (금소법 검증, 소식지 파싱, 정보성 키워드)

@dataclass
class AIJob:
    job_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    user_id: str = ""
    feature: str = ""         # "content_generate", "policy_analyze", "suggest_topics" 등
    priority: AIPriority = AIPriority.NORMAL
    status: str = "queued"    # queued, processing, completed, failed
    result: dict = field(default_factory=dict)
    error: str = ""
    created_at: datetime = field(default_factory=datetime.now)
    queue_position: int = 0

class UnifiedAIQueue:
    def __init__(self, max_concurrent: int = 5):
        self._semaphore = asyncio.Semaphore(max_concurrent)
        self._jobs: dict[str, AIJob] = {}
        self._queue_count = 0  # 대기 중인 작업 수
    
    def create_job(self, user_id: str, feature: str, priority: AIPriority = AIPriority.NORMAL) -> AIJob:
        job = AIJob(user_id=user_id, feature=feature, priority=priority)
        self._jobs[job.job_id] = job
        self._queue_count += 1
        job.queue_position = self._queue_count
        return job
    
    async def submit(self, job: AIJob, coro):
        """큐에 작업 제출. Semaphore로 동시 실행 제한."""
        try:
            async with self._semaphore:
                job.status = "processing"
                self._queue_count = max(0, self._queue_count - 1)
                result = await coro
                job.status = "completed"
                job.result = result or {}
                return result
        except Exception as e:
            job.status = "failed"
            job.error = str(e)[:500]
            raise
    
    def get_job(self, job_id: str) -> AIJob | None:
        return self._jobs.get(job_id)
    
    def get_queue_status(self) -> dict:
        active = sum(1 for j in self._jobs.values() if j.status == "processing")
        queued = sum(1 for j in self._jobs.values() if j.status == "queued")
        return {"active": active, "queued": queued, "max_concurrent": self._semaphore._value}

# 싱글톤
ai_queue = UnifiedAIQueue(max_concurrent=5)
```

### 2. 모든 AI 엔드포인트에서 통합 큐 사용

기존 직접 subprocess 호출 → `ai_queue.submit()` 통해 호출:

```python
from ai_queue import ai_queue, AIPriority

# 예: 주제 추천
@app.post("/api/insuro/suggest-topics")
async def suggest_topics(...):
    job = ai_queue.create_job(user_id, "suggest_topics", AIPriority.NORMAL)
    
    async def _run():
        result = subprocess.run(["claude", "-p", prompt, ...], ...)
        return json.loads(result.stdout)
    
    result = await ai_queue.submit(job, _run())
    return {"topics": result, "queue_position": job.queue_position}
```

### 3. 적용 대상 엔드포인트 (우선순위별)

**P1 URGENT (사용자 대기 중):**
- `/api/insuro/generate-content` — 콘텐츠 생성 (기존 generation_queue → ai_queue로 통합)
- `/api/insuro/analyze-policy` — 증권 분석
- `/api/insuro/newsletter-chat` — 소식지 AI 채팅
- `/api/insuro/premium-chat` — 보험료 AI 채팅

**P2 NORMAL:**
- `/api/insuro/suggest-topics` — 주제 추천
- `/api/insuro/analyze-customer` — 고객 분석
- `/api/insuro/evaluate-consultation` — 상담 평가
- `/api/insuro/keywords/analyze` — 정보성 키워드

**P3 BACKGROUND:**
- `/api/insuro/parse-premium-file` — 소식지/보험료 파싱
- 금소법 더블체크 (_run_compliance_check_async)
- `/api/insuro/onboarding/ai-generate` — 온보딩 AI

### 4. 프론트엔드 대기 표시
모든 AI 요청 시 응답에 `queue_position` 포함:
```json
{ "job_id": "...", "queue_position": 3, "status": "queued" }
```
프론트에서: "대기 중 (3번째)" → "처리 중..." → 결과 표시

### 5. 기존 generation_queue.py와의 관계
- `generation_queue.py`는 **제거하지 않고** 통합 큐의 wrapper로 전환
- 또는 `ai_queue.py`가 `generation_queue.py`의 기능을 완전 흡수

## affected_files
- `server/ai_queue.py` (신규 — 통합 AI 큐 모듈)
- `server/main.py` (수정 — 모든 AI 엔드포인트에서 ai_queue 사용)
- `server/generation_queue.py` (수정 — ai_queue 통합 또는 wrapper)

## 검증 시나리오
1. 동시 AI 요청 6건 → 5건 처리 중 + 1건 대기
2. 대기 작업에 queue_position 반환
3. URGENT 작업이 BACKGROUND보다 먼저 실행 (우선순위 동작)
4. get_queue_status → active/queued 정확 반환
5. 기존 콘텐츠 생성 정상 작동 (호환성)
6. pytest 전량 통과
7. npm run build 성공
