feat: RAG 임베딩 자동 동기화 + AI 서비스 개선

- 부적합 라이프사이클 전 과정에서 Qdrant 임베딩 자동 동기화
  - 관리함 5개 저장 함수 + 수신함 상태 변경 시 fire-and-forget sync
  - 30분 주기 전체 재동기화 안전망 (FastAPI lifespan 백그라운드 태스크)
  - build_document_text에 카테고리(final_category/category) 포함
- RAG 질의에 DB 통계 집계 지원 (카테고리별/부서별 건수)
- Qdrant client.search → query_points API 마이그레이션
- AI 어시스턴트 페이지 권한 추가 (tkuser)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-12 13:05:32 +09:00
parent 65db787f92
commit 5b1b89254c
11 changed files with 154 additions and 8 deletions

View File

@@ -1,8 +1,11 @@
import logging
import uuid
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue
from config import settings
logger = logging.getLogger(__name__)
class VectorStore:
def __init__(self):
@@ -51,17 +54,19 @@ class VectorStore:
) -> list[dict]:
query_filter = self._build_filter(where) if where else None
try:
results = self.client.search(
response = self.client.query_points(
collection_name=self.collection,
query_vector=embedding,
query=embedding,
limit=n_results,
query_filter=query_filter,
with_payload=True,
)
except Exception:
except Exception as e:
logger.error(f"Qdrant search failed: {e}", exc_info=True)
return []
items = []
for hit in results:
for hit in response.points:
payload = hit.payload or {}
item = {
"id": payload.get("original_id", str(hit.id)),