feat(ui): 처리 머신 보드 — 누가 일하나 (안2) + ETA·전 페이지 스트립/드로어 (안5/6 라이트)
plan ds-processing-ui-6an (시안 choice 채택: 안2 1차 + 안5/6 지원): - GET /api/queue/overview — 머신(GPU/맥미니/맥북) 귀속 라이브 집계 5쿼리, 마이그레이션 0. summarize 풀 완료 실적은 documents.ai_model_version 조인으로 맥북/맥미니 분리, 보류(deferred_until)=맥북 카드 귀속, state=active/deferred/idle. raw 모델명 비노출 - 홈: 처리 머신 보드(3열 카드 + 지금 처리 중 제목) + ETA 라인(유입 우세 시 null 명시), 기존 stage 테이블은 details 접힘으로 강등 (구조 개편) - 전 페이지: 상태 스트립(처리중·대기·실패·맥북 칩) + 우측 드로어(QueueDrawer, dialog a11y) — 공유 60s 폴링 store, 경량 fetch(401 강제 logout 부수효과 회피) - tests: 판정부 30건 (귀속/풀 분리/state 9케이스/ETA 경계/trend 버킷/계약 shape) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""처리 머신 보드 API — GET /api/queue/overview (plan ds-processing-ui-6an).
|
||||
|
||||
홈 stage 평면 테이블을 "머신 관점 보드(누가 일하나)"로 — 집계 로직은
|
||||
services/queue_overview.py (순수 판정부 분리). 응답 스키마는 FE 와 계약 고정.
|
||||
응답에 raw 모델명 노출 금지 — 머신 label 만.
|
||||
"""
|
||||
|
||||
from typing import Annotated, Literal
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.auth import get_current_user
|
||||
from core.database import get_session
|
||||
from models.user import User
|
||||
from services.queue_overview import build_overview
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class CurrentItem(BaseModel):
|
||||
"""머신이 지금 처리 중인 문서 (최대 2건)."""
|
||||
document_id: int
|
||||
title: str
|
||||
stage: str
|
||||
|
||||
|
||||
class MachineCard(BaseModel):
|
||||
"""머신 카드 — stage 귀속 합산 + 완료 실적(summarize 는 풀 분리) + state."""
|
||||
key: Literal["gpu", "macmini", "macbook"]
|
||||
label: str
|
||||
state: Literal["active", "deferred", "idle"]
|
||||
stages: list[str]
|
||||
pending: int
|
||||
processing: int
|
||||
failed: int
|
||||
done_1h: int
|
||||
done_today: int
|
||||
deferred_pending: int
|
||||
current: list[CurrentItem]
|
||||
|
||||
|
||||
class SummarizeEta(BaseModel):
|
||||
"""summarize 풀 ETA — done > inflow 일 때만 eta_minutes 산출."""
|
||||
pending: int
|
||||
done_rate_1h: int
|
||||
inflow_rate_1h: int
|
||||
eta_minutes: int | None
|
||||
|
||||
|
||||
class TrendBucket(BaseModel):
|
||||
"""summarize 24h 추이 버킷 — hour 는 KST "HH:00" 라벨."""
|
||||
hour: str
|
||||
inflow: int
|
||||
done: int
|
||||
|
||||
|
||||
class Totals(BaseModel):
|
||||
"""전 stage 합계."""
|
||||
pending: int
|
||||
processing: int
|
||||
failed: int
|
||||
|
||||
|
||||
class QueueOverviewResponse(BaseModel):
|
||||
machines: list[MachineCard]
|
||||
summarize_eta: SummarizeEta
|
||||
trend_24h: list[TrendBucket]
|
||||
totals: Totals
|
||||
|
||||
|
||||
@router.get("/overview", response_model=QueueOverviewResponse)
|
||||
async def get_queue_overview(
|
||||
user: Annotated[User, Depends(get_current_user)],
|
||||
session: Annotated[AsyncSession, Depends(get_session)],
|
||||
):
|
||||
"""머신 관점 처리 보드 + summarize ETA 집계 (라이브 계산, 신규 테이블 0)"""
|
||||
return QueueOverviewResponse.model_validate(await build_overview(session))
|
||||
Reference in New Issue
Block a user