음성 재생과 운영 배포 정리
This commit is contained in:
parent
8ed185ce6c
commit
ac7db95542
1020 changed files with 46863 additions and 2175 deletions
|
|
@ -22,7 +22,7 @@ from pydantic import BaseModel, Field
|
|||
|
||||
from ..db import acquire, get_pool
|
||||
from ..deps import AIView, Principal, Role, require_role
|
||||
from ..services import rag
|
||||
from ..services import live_coach, rag
|
||||
|
||||
router = APIRouter(prefix="/kb", tags=["kb"])
|
||||
|
||||
|
|
@ -104,6 +104,24 @@ class IndexResponse(BaseModel):
|
|||
degraded: bool = False
|
||||
|
||||
|
||||
class LiveCoachSourcePackSyncItem(BaseModel):
|
||||
source_id: str
|
||||
doc_id: Optional[int]
|
||||
chunks_indexed: int
|
||||
skipped_unchanged: bool
|
||||
embedded: bool
|
||||
degraded: bool = False
|
||||
|
||||
|
||||
class LiveCoachSourcePackSyncResponse(BaseModel):
|
||||
sources_upserted: int
|
||||
chunks_indexed: int
|
||||
skipped_unchanged: int
|
||||
embedded: bool
|
||||
degraded: bool = False
|
||||
items: list[LiveCoachSourcePackSyncItem] = Field(default_factory=list)
|
||||
|
||||
|
||||
# ── 헬퍼: rag.NotConfigured → 503 ───────────────────────
|
||||
def _to_chunk_out(c: rag.RetrievedChunk) -> ChunkOut:
|
||||
return ChunkOut(
|
||||
|
|
@ -222,6 +240,7 @@ async def eval_grounding(body: KBSearchRequest) -> KBSearchResponse:
|
|||
query=body.query,
|
||||
k=body.k,
|
||||
kinds=body.kb_kind,
|
||||
source_ids=body.source_id,
|
||||
rerank=body.rerank,
|
||||
)
|
||||
try:
|
||||
|
|
@ -319,3 +338,80 @@ async def index_document(
|
|||
embedded=result.embedded,
|
||||
degraded=result.degraded,
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/live-coach/source-packs/sync",
|
||||
response_model=LiveCoachSourcePackSyncResponse,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
async def sync_live_coach_source_packs(
|
||||
principal: Annotated[Principal, Depends(require_role(Role.ADMIN))],
|
||||
) -> LiveCoachSourcePackSyncResponse:
|
||||
"""허가된 라이브 코칭 source pack을 kb.source/kb.chunk RAG 색인에 적재한다.
|
||||
|
||||
로컬 `data/kb/live_coaching_*.json`은 UI 즉시 코칭의 기본 근거이고, 이 경로는 같은 자료를
|
||||
evaluator RAG 검색에도 올린다. source row를 먼저 upsert한 뒤 content_hash 기반 증분 색인을
|
||||
수행한다. 임베딩 모델 미가용 시 BM25-only degraded 색인으로 이어진다.
|
||||
"""
|
||||
source_rows = live_coach.build_rag_source_rows()
|
||||
index_payloads = live_coach.build_rag_index_payloads()
|
||||
if not source_rows or not index_payloads:
|
||||
raise HTTPException(
|
||||
status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="live coach source packs are empty",
|
||||
)
|
||||
|
||||
items: list[LiveCoachSourcePackSyncItem] = []
|
||||
source_row_by_id = {row["source_id"]: row for row in source_rows}
|
||||
try:
|
||||
async with acquire() as conn:
|
||||
for row in source_rows:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO kb.source
|
||||
(source_id, title, kb_kind, license_class, origin_path, citation, external_llm_ok)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (source_id) DO UPDATE SET
|
||||
title = EXCLUDED.title,
|
||||
kb_kind = EXCLUDED.kb_kind,
|
||||
license_class = EXCLUDED.license_class,
|
||||
origin_path = EXCLUDED.origin_path,
|
||||
citation = EXCLUDED.citation,
|
||||
external_llm_ok = EXCLUDED.external_llm_ok
|
||||
""",
|
||||
row["source_id"],
|
||||
row["title"],
|
||||
row["kb_kind"],
|
||||
row["license_class"],
|
||||
row["origin_path"],
|
||||
row["citation"],
|
||||
row["external_llm_ok"],
|
||||
)
|
||||
for payload in index_payloads:
|
||||
if payload["source_id"] not in source_row_by_id:
|
||||
continue
|
||||
result = await rag.index_document(conn, rag.IndexRequest(**payload))
|
||||
items.append(
|
||||
LiveCoachSourcePackSyncItem(
|
||||
source_id=payload["source_id"],
|
||||
doc_id=result.doc_id,
|
||||
chunks_indexed=result.chunks_indexed,
|
||||
skipped_unchanged=result.skipped_unchanged,
|
||||
embedded=result.embedded,
|
||||
degraded=result.degraded,
|
||||
)
|
||||
)
|
||||
except rag.NotConfigured as exc:
|
||||
raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE, detail=f"RAG not configured: {exc}") from exc
|
||||
except RuntimeError as exc:
|
||||
raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE, detail=f"DB not ready: {exc}") from exc
|
||||
|
||||
return LiveCoachSourcePackSyncResponse(
|
||||
sources_upserted=len(source_rows),
|
||||
chunks_indexed=sum(item.chunks_indexed for item in items),
|
||||
skipped_unchanged=sum(1 for item in items if item.skipped_unchanged),
|
||||
embedded=all(item.embedded for item in items) if items else False,
|
||||
degraded=any(item.degraded for item in items),
|
||||
items=items,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue