Skip to content

Commit c53046c

Browse files
jinsoojinsoo
authored andcommitted
pipeline v1-2
1 parent dfdc39f commit c53046c

30 files changed

+1981
-5265
lines changed

qdrant_db/.lock

Lines changed: 0 additions & 1 deletion
This file was deleted.
-68 KB
Binary file not shown.
-1.47 MB
Binary file not shown.

qdrant_db/meta.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Core dependencies
44
transformers>=4.30.0
5-
#torch>=2.0.0
5+
torch>=2.0.0
66
sentence-transformers>=2.2.0
77
qdrant-client>=1.6.0
88
#accelerate>=0.20.0
@@ -22,6 +22,7 @@ pandas>=2.0.0
2222
# Utilities
2323
python-dotenv>=1.0.0
2424
requests>=2.31.0
25+
httpx>=0.25.0
2526
psutil>=7.0.0
2627

2728
# GPU Optimization (Phase 1 & 2)

src/__init__.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,10 @@
1818
prepare_qdrant_points,
1919
get_restaurant_reviews,
2020
query_similar_reviews,
21-
get_reviews_with_images,
2221
)
23-
from .llm_utils import (
24-
LLMUtils,
25-
summarize_reviews,
26-
)
27-
from .strength_extraction import (
28-
StrengthExtractionPipeline,
22+
from .llm_utils import LLMUtils
23+
from .comparison import (
24+
ComparisonPipeline,
2925
)
3026

3127
__all__ = [
@@ -36,9 +32,7 @@
3632
"prepare_qdrant_points",
3733
"get_restaurant_reviews",
3834
"query_similar_reviews",
39-
"get_reviews_with_images",
4035
"LLMUtils",
41-
"summarize_reviews",
42-
"StrengthExtractionPipeline",
36+
"ComparisonPipeline",
4337
]
4438

src/api/dependencies.py

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
from ..vector_search import VectorSearch
1313
from ..llm_utils import LLMUtils
1414
from ..metrics_collector import MetricsCollector
15+
from ..cpu_monitor import get_or_create_benchmark_cpu_monitor
16+
from ..gpu_monitor import get_or_create_benchmark_gpu_monitor
1517

1618
# 의존성 싱글톤 (매 요청 인스턴스 생성 방지 — Encoder/Qdrant는 @lru_cache, 나머지는 모듈 캐시)
1719
_vector_search_singleton: Optional[VectorSearch] = None
1820
_sentiment_analyzer_singleton: Optional[SentimentAnalyzer] = None
21+
_default_metrics_collector: Optional[MetricsCollector] = None
22+
_benchmark_metrics_collector: Optional[MetricsCollector] = None
1923

2024

2125
@lru_cache()
@@ -44,15 +48,56 @@ def get_qdrant_client() -> QdrantClient:
4448
return QdrantClient(path=qdrant_path)
4549

4650

47-
@lru_cache()
48-
def get_metrics_collector() -> MetricsCollector:
49-
"""메트릭 수집기 싱글톤"""
50-
return MetricsCollector(
51-
enable_logging=Config.METRICS_ENABLE_LOGGING,
52-
enable_db=Config.METRICS_ENABLE_DB,
53-
db_path=Config.METRICS_DB_PATH,
54-
log_dir=Config.METRICS_LOG_DIR,
55-
)
51+
def get_metrics_collector(
52+
x_benchmark: Optional[str] = Header(None, alias="X-Benchmark"),
53+
x_enable_cpu_monitor: Optional[str] = Header(None, alias="X-Enable-CPU-Monitor"),
54+
x_enable_gpu_monitor: Optional[str] = Header(None, alias="X-Enable-GPU-Monitor"),
55+
) -> MetricsCollector:
56+
"""
57+
메트릭 수집기 싱글톤.
58+
- X-Benchmark: true 이면 요청 메트릭 수집 활성화 (logs + metrics.db).
59+
- X-Enable-CPU-Monitor: true 이면 CPU 모니터링만 활성화 (logs/cpu_usage.log).
60+
- X-Enable-GPU-Monitor: true 이면 서버 GPU 모니터링만 활성화 (logs/gpu_usage.log).
61+
- 헤더는 독립적: 메트릭만 / CPU만 / GPU만 / 조합 가능.
62+
"""
63+
global _default_metrics_collector, _benchmark_metrics_collector
64+
65+
_truth = ("true", "1", "yes")
66+
want_cpu = x_enable_cpu_monitor and str(x_enable_cpu_monitor).strip().lower() in _truth
67+
want_gpu = x_enable_gpu_monitor and str(x_enable_gpu_monitor).strip().lower() in _truth
68+
want_metrics = x_benchmark and str(x_benchmark).strip().lower() in _truth
69+
70+
if want_cpu:
71+
get_or_create_benchmark_cpu_monitor()
72+
if want_gpu:
73+
get_or_create_benchmark_gpu_monitor()
74+
75+
if want_metrics:
76+
if _benchmark_metrics_collector is None:
77+
_benchmark_metrics_collector = MetricsCollector(
78+
enable_logging=True,
79+
enable_db=True,
80+
db_path=Config.METRICS_DB_PATH,
81+
log_dir=Config.METRICS_LOG_DIR,
82+
)
83+
return _benchmark_metrics_collector
84+
85+
if _default_metrics_collector is None:
86+
if not Config.METRICS_AND_LOGGING_ENABLE:
87+
_default_metrics_collector = MetricsCollector(
88+
enable_logging=False,
89+
enable_db=False,
90+
db_path=Config.METRICS_DB_PATH,
91+
log_dir=Config.METRICS_LOG_DIR,
92+
)
93+
else:
94+
_default_metrics_collector = MetricsCollector(
95+
enable_logging=Config.METRICS_ENABLE_LOGGING,
96+
enable_db=Config.METRICS_ENABLE_DB,
97+
db_path=Config.METRICS_DB_PATH,
98+
log_dir=Config.METRICS_LOG_DIR,
99+
)
100+
return _default_metrics_collector
56101

57102

58103
@lru_cache()

src/api/main.py

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
FastAPI 메인 애플리케이션
33
"""
44

5-
from fastapi import FastAPI
5+
from fastapi import FastAPI, Request
66
from fastapi.middleware.cors import CORSMiddleware
7+
from fastapi.responses import JSONResponse
8+
from fastapi.exceptions import RequestValidationError
9+
from starlette.exceptions import HTTPException as StarletteHTTPException
710
from contextlib import asynccontextmanager
811
import logging
912
import sys
13+
import uuid
1014

11-
from .routers import sentiment, vector, llm, restaurant, test
15+
from .routers import sentiment, vector, llm, test
16+
from ..cpu_monitor import get_cpu_monitor
1217

1318
# 로거 설정 (콘솔 출력)
1419
# basicConfig는 한 번만 실행되므로, root 로거에 직접 핸들러 추가
@@ -38,8 +43,17 @@ async def lifespan(app: FastAPI):
3843
"""애플리케이션 생명주기 관리"""
3944
# 시작 시 초기화
4045
logger.info("FastAPI 애플리케이션 시작")
46+
47+
# CPU 모니터 시작 (Config.CPU_MONITOR_ENABLE=true일 때만)
48+
cpu_monitor = get_cpu_monitor()
49+
if cpu_monitor:
50+
cpu_monitor.start()
51+
4152
yield
53+
4254
# 종료 시 정리
55+
if cpu_monitor:
56+
await cpu_monitor.stop()
4357
logger.info("FastAPI 애플리케이션 종료")
4458

4559

@@ -50,6 +64,65 @@ async def lifespan(app: FastAPI):
5064
lifespan=lifespan,
5165
)
5266

67+
# 요청 ID 미들웨어 (응답 헤더에도 포함)
68+
@app.middleware("http")
69+
async def add_request_id(request: Request, call_next):
70+
request_id = request.headers.get("X-Request-Id") or request.headers.get("X-Request-ID") or str(uuid.uuid4())
71+
request.state.request_id = request_id
72+
response = await call_next(request)
73+
response.headers["X-Request-Id"] = request_id
74+
return response
75+
76+
77+
def _error_payload(*, code: int, message: str, details, request_id: str) -> dict:
78+
return {"code": code, "message": message, "details": details, "request_id": request_id}
79+
80+
81+
@app.exception_handler(RequestValidationError)
82+
async def request_validation_exception_handler(request: Request, exc: RequestValidationError):
83+
request_id = getattr(request.state, "request_id", str(uuid.uuid4()))
84+
return JSONResponse(
85+
status_code=422,
86+
content=_error_payload(
87+
code=422,
88+
message="Validation error",
89+
details=exc.errors(),
90+
request_id=request_id,
91+
),
92+
)
93+
94+
95+
@app.exception_handler(StarletteHTTPException)
96+
async def starlette_http_exception_handler(request: Request, exc: StarletteHTTPException):
97+
request_id = getattr(request.state, "request_id", str(uuid.uuid4()))
98+
# 404 등 라우팅 단계 HTTP 예외 포함
99+
detail = getattr(exc, "detail", None)
100+
message = str(detail) if detail is not None else "HTTP error"
101+
return JSONResponse(
102+
status_code=exc.status_code,
103+
content=_error_payload(
104+
code=exc.status_code,
105+
message=message,
106+
details=detail,
107+
request_id=request_id,
108+
),
109+
)
110+
111+
112+
@app.exception_handler(Exception)
113+
async def unhandled_exception_handler(request: Request, exc: Exception):
114+
request_id = getattr(request.state, "request_id", str(uuid.uuid4()))
115+
logger.error("Unhandled exception: %s", exc, exc_info=True)
116+
return JSONResponse(
117+
status_code=500,
118+
content=_error_payload(
119+
code=500,
120+
message="Internal server error",
121+
details=None,
122+
request_id=request_id,
123+
),
124+
)
125+
53126
# CORS 설정
54127
app.add_middleware(
55128
CORSMiddleware,
@@ -63,7 +136,6 @@ async def lifespan(app: FastAPI):
63136
app.include_router(sentiment.router, prefix="/api/v1/sentiment", tags=["sentiment"])
64137
app.include_router(vector.router, prefix="/api/v1/vector", tags=["vector"])
65138
app.include_router(llm.router, prefix="/api/v1/llm", tags=["llm"])
66-
app.include_router(restaurant.router, prefix="/api/v1/restaurants", tags=["restaurants"])
67139
app.include_router(test.router, prefix="/api/v1/test", tags=["test"])
68140

69141

0 commit comments

Comments
 (0)