multifuly commited on
Commit
5bf6c06
·
verified ·
1 Parent(s): ed9c7a2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -67
app.py CHANGED
@@ -1,67 +1,92 @@
1
- """
2
- Hugging Face Spaces (Docker) — Contrastive 질의 임베딩 API.
3
-
4
- 모델은 HF Hub에서 로드 (환경변수 HF_MODEL_ID, 예: <org>/<model-id>).
5
- POST로 텍스트 받아 768-dim 벡터 반환. 백엔드 RAG_CONTRASTIVE_EMBEDDING_URL 연동용.
6
-
7
- 환경변수:
8
- - HF_MODEL_ID: SentenceTransformer 모델 ID (필수)
9
- - HF_TOKEN: 비공개 리포 접근용 토큰 (선택)
10
- """
11
- import os
12
- from typing import List, Union
13
-
14
- from fastapi import FastAPI
15
- from fastapi.middleware.cors import CORSMiddleware
16
- from pydantic import BaseModel
17
-
18
- MODEL_ID = (os.environ.get("HF_MODEL_ID") or "").strip()
19
- HF_TOKEN = (os.environ.get("HF_TOKEN") or "").strip() or None
20
-
21
- model = None
22
-
23
- app = FastAPI(title="Contrastive Embedding API")
24
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
25
-
26
-
27
- class EmbedRequest(BaseModel):
28
- """백엔드 contrastive_retriever가 보내는 형식."""
29
- inputs: str
30
-
31
-
32
- def load_model():
33
- global model
34
- from sentence_transformers import SentenceTransformer
35
- print(f"[Embed] 모델 로딩: {MODEL_ID}")
36
- model = SentenceTransformer(MODEL_ID, token=HF_TOKEN)
37
- print("[Embed] 로드 완료.")
38
-
39
-
40
- @app.on_event("startup")
41
- def startup():
42
- if MODEL_ID:
43
- load_model()
44
- else:
45
- print("[Embed] HF_MODEL_ID 미설정. 설정 후 재시작.")
46
-
47
-
48
- @app.post("/")
49
- def embed(body: EmbedRequest) -> Union[List[List[float]], dict]:
50
- """
51
- 질의 문자열을 768-dim 벡터로 변환.
52
- 응답: [[float,...]] (백엔드가 기대하는 형식) 또는 {"embedding": [float,...]}
53
- """
54
- global model
55
- if not model:
56
- return {"embedding": [], "error": "HF_MODEL_ID not set"}
57
- text = (body.inputs or "").strip()
58
- if not text:
59
- return {"embedding": [], "error": "empty inputs"}
60
- vec = model.encode([text], normalize_embeddings=True)
61
- # 백엔드: list of list 또는 {"embedding": ...} 둘 다 처리
62
- return vec.tolist()
63
-
64
-
65
- @app.get("/health")
66
- def health():
67
- return {"status": "ok", "model_loaded": model is not None}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hugging Face Spaces (Docker) — Contrastive 질의 임베딩 API.
3
+
4
+ 모델은 HF Hub에서 로드 (환경변수 HF_MODEL_ID, 예: <org>/<model-id>).
5
+ POST로 텍스트 받아 768-dim 벡터 반환. 백엔드 RAG_CONTRASTIVE_EMBEDDING_URL 연동용.
6
+
7
+ 환경변수:
8
+ - HF_MODEL_ID: SentenceTransformer 모델 ID (필수)
9
+ - HF_TOKEN: 비공개 리포 접근용 토큰 (선택)
10
+ """
11
+ import os
12
+ from typing import List, Union
13
+
14
+ from fastapi import FastAPI
15
+ from fastapi.middleware.cors import CORSMiddleware
16
+ from pydantic import BaseModel
17
+
18
+ MODEL_ID = (os.environ.get("HF_MODEL_ID") or "").strip()
19
+ HF_TOKEN = (os.environ.get("HF_TOKEN") or "").strip() or None
20
+
21
+ model = None
22
+
23
+ app = FastAPI(title="Contrastive Embedding API")
24
+ app.add_middleware(
25
+ CORSMiddleware,
26
+ allow_origins=["*"],
27
+ allow_methods=["*"],
28
+ allow_headers=["*"],
29
+ )
30
+
31
+
32
+ class EmbedRequest(BaseModel):
33
+ """백엔드 contrastive_retriever가 보내는 형식."""
34
+ inputs: str
35
+
36
+
37
+ def load_model() -> None:
38
+ global model
39
+ from sentence_transformers import SentenceTransformer
40
+
41
+ print(f"[Embed] 모델 로딩: {MODEL_ID}")
42
+ model = SentenceTransformer(MODEL_ID, token=HF_TOKEN)
43
+ print("[Embed] 로드 완료.")
44
+
45
+
46
+ @app.on_event("startup")
47
+ def startup() -> None:
48
+ if MODEL_ID:
49
+ load_model()
50
+ else:
51
+ print("[Embed] HF_MODEL_ID 미설정. 설정 후 재시작.")
52
+
53
+
54
+ @app.post("/")
55
+ def embed(body: EmbedRequest) -> Union[List[List[float]], dict]:
56
+ """
57
+ 질의 문자열을 768-dim 벡터로 변환.
58
+ 응답: [[float,...]] (백엔드가 기대하는 형식) 또는 {"embedding": [float,...]}
59
+ """
60
+ global model
61
+ if not model:
62
+ return {"embedding": [], "error": "HF_MODEL_ID not set"}
63
+
64
+ text = (body.inputs or "").strip()
65
+ if not text:
66
+ return {"embedding": [], "error": "empty inputs"}
67
+
68
+ vec = model.encode([text], normalize_embeddings=True)
69
+ # 백엔드: list of list 또는 {"embedding": ...} 둘 다 처리
70
+ return vec.tolist()
71
+
72
+
73
+ @app.get("/")
74
+ def root():
75
+ """
76
+ Hugging Face Spaces / 컨테이너 헬스체크용 루트 엔드포인트.
77
+
78
+ - GET / → 200 OK
79
+ - GET /?logs=... → 200 OK (path는 / 그대로, query만 다름)
80
+ - UptimeRobot HTTP(S) 모니터의 HEAD / 도 FastAPI가 자동 처리
81
+ """
82
+ return {
83
+ "status": "ok",
84
+ "service": "contrastive-embedding",
85
+ "model_loaded": model is not None,
86
+ }
87
+
88
+
89
+ @app.get("/health")
90
+ def health():
91
+ """단순 헬스 체크 엔드포인트."""
92
+ return {"status": "ok", "model_loaded": model is not None}