crgmail commited on
Commit
e1ba2b5
ยท
verified ยท
1 Parent(s): bdfdac7

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +35 -0
  2. README.md +16 -5
  3. app.py +326 -0
  4. requirements.txt +9 -0
Dockerfile ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ # HF Spaces ่ฆๆฑ‚ไฝฟ็”จ 7860 ็ซฏๅฃ๏ผŒ้ž root ็”จๆˆท
4
+ RUN useradd -m -u 1000 user
5
+ WORKDIR /app
6
+
7
+ # ๅฎ‰่ฃ…็ณป็ปŸไพ่ต–
8
+ RUN apt-get update && apt-get install -y \
9
+ libgomp1 \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # ๅ…ˆ่ฃ… CPU ็‰ˆ PyTorch๏ผˆไฝ“็งฏๆฏ” CUDA ็‰ˆๅฐ ~2GB๏ผ‰
13
+ RUN pip install --no-cache-dir \
14
+ torch==2.3.1+cpu \
15
+ --index-url https://download.pytorch.org/whl/cpu
16
+
17
+ # ๅฎ‰่ฃ…ๅ…ถไฝ™ไพ่ต–
18
+ COPY requirements.txt .
19
+ RUN pip install --no-cache-dir -r requirements.txt
20
+
21
+ # โœ… ๆž„ๅปบ้˜ถๆฎต้ข„ไธ‹่ฝฝๆจกๅž‹๏ผŒๅฝปๅบ•้ฟๅ…่ฟ่กŒๆ—ถๅ†ทๅฏๅŠจไธ‹่ฝฝ
22
+ # ๆจกๅž‹ๆ–‡ไปถ็ƒ˜็„™่ฟ› Docker ้•œๅƒๅฑ‚
23
+ ENV HF_HOME=/app/hf_cache
24
+ RUN python -c "\
25
+ from huggingface_hub import snapshot_download; \
26
+ snapshot_download('BAAI/bge-m3', ignore_patterns=['*.msgpack','*.h5','flax_model*','tf_model*','rust_model*']); \
27
+ snapshot_download('BAAI/bge-reranker-v2-m3', ignore_patterns=['*.msgpack','*.h5','flax_model*','tf_model*','rust_model*']); \
28
+ print('Models downloaded successfully')"
29
+
30
+ COPY --chown=user:user . .
31
+
32
+ USER user
33
+ EXPOSE 7860
34
+
35
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
README.md CHANGED
@@ -1,10 +1,21 @@
1
  ---
2
- title: Bge
3
- emoji: ๐ŸŒ
4
- colorFrom: purple
5
- colorTo: blue
6
  sdk: docker
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: BGE Embedding Reranker API
3
+ emoji: ๐Ÿ”
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: docker
7
  pinned: false
8
  ---
9
 
10
+ # BGE M3 Embedding & Reranker API
11
+
12
+ OpenAI ๅ…ผๅฎนๆŽฅๅฃ๏ผŒ้ƒจ็ฝฒ BAAI/bge-m3 ๅ’Œ BAAI/bge-reranker-v2-m3ใ€‚
13
+ ```
14
+
15
+ ---
16
+
17
+ ## ้ƒจ็ฝฒๆญฅ้ชค
18
+
19
+ **1. ๅˆ›ๅปบ Space**
20
+ ```
21
+ huggingface.co โ†’ New Space โ†’ SDK ้€‰ Docker โ†’ ๅฏ่งๆ€ง่ฎพไธบ Public
app.py ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import threading
4
+ import asyncio
5
+ from contextlib import asynccontextmanager
6
+ from typing import List, Optional, Union, Any
7
+
8
+ import httpx
9
+ import numpy as np
10
+ from fastapi import FastAPI, HTTPException, Request, Depends
11
+ from fastapi.middleware.cors import CORSMiddleware
12
+ from fastapi.responses import JSONResponse
13
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
14
+ from pydantic import BaseModel, Field
15
+
16
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
+ # ้…็ฝฎ
18
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
19
+ API_KEY = os.environ.get("API_KEY", "")
20
+ if not API_KEY:
21
+ print("[WARNING] API_KEY environment variable is not set, all requests will be rejected!")
22
+ EMBED_MODEL_ID = "BAAI/bge-m3"
23
+ RERANK_MODEL_ID = "BAAI/bge-reranker-v2-m3"
24
+ SELF_URL = "http://localhost:7860" # ไฟๆดป ping ็›ฎๆ ‡
25
+ KEEPALIVE_SEC = 240 # ๆฏ 4 ๅˆ†้’Ÿ ping ไธ€ๆฌก๏ผˆHF 5ๅˆ†้’Ÿ่ถ…ๆ—ถ๏ผ‰
26
+ HF_HOME = os.environ.get("HF_HOME", "/app/hf_cache")
27
+
28
+ os.environ["HF_HOME"] = HF_HOME
29
+
30
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
31
+ # ๅ…จๅฑ€ๆจกๅž‹็Šถๆ€
32
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
33
+ models: dict = {
34
+ "embed": None,
35
+ "reranker": None,
36
+ "embed_status": "loading", # loading | ready | error
37
+ "rerank_status": "loading",
38
+ "start_time": time.time(),
39
+ }
40
+
41
+
42
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
43
+ # ๆจกๅž‹ๅŠ ่ฝฝ๏ผˆๅผ‚ๆญฅๅŽๅฐ๏ผŒไธ้˜ปๅกžๅฏๅŠจ๏ผ‰
44
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
45
+ def load_models():
46
+ try:
47
+ from FlagEmbedding import BGEM3FlagModel
48
+ models["embed_status"] = "loading"
49
+ models["embed"] = BGEM3FlagModel(
50
+ EMBED_MODEL_ID,
51
+ use_fp16=False, # CPU ไธๆ”ฏๆŒ fp16
52
+ devices=["cpu"],
53
+ )
54
+ models["embed_status"] = "ready"
55
+ print("[INFO] Embedding model loaded โœ“")
56
+ except Exception as e:
57
+ models["embed_status"] = f"error: {e}"
58
+ print(f"[ERROR] Embedding model failed: {e}")
59
+
60
+ try:
61
+ from FlagEmbedding import FlagReranker
62
+ models["rerank_status"] = "loading"
63
+ models["reranker"] = FlagReranker(
64
+ RERANK_MODEL_ID,
65
+ use_fp16=False,
66
+ )
67
+ models["rerank_status"] = "ready"
68
+ print("[INFO] Reranker model loaded โœ“")
69
+ except Exception as e:
70
+ models["rerank_status"] = f"error: {e}"
71
+ print(f"[ERROR] Reranker model failed: {e}")
72
+
73
+
74
+ def keepalive_loop():
75
+ """ๅŽๅฐ็บฟ็จ‹๏ผšๅฎšๆ—ถ ping ่‡ช่บซ๏ผŒ้˜ฒๆญข HF Spaces ไผ‘็œ """
76
+ time.sleep(60) # ็ญ‰ๅฏๅŠจๅฎŒๆˆ
77
+ while True:
78
+ try:
79
+ import httpx as _httpx
80
+ _httpx.get(f"{SELF_URL}/health", timeout=10)
81
+ print(f"[KEEPALIVE] ping ok @ {time.strftime('%H:%M:%S')}")
82
+ except Exception as e:
83
+ print(f"[KEEPALIVE] ping failed: {e}")
84
+ time.sleep(KEEPALIVE_SEC)
85
+
86
+
87
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
88
+ # ็”Ÿๅ‘ฝๅ‘จๆœŸ
89
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
90
+ @asynccontextmanager
91
+ async def lifespan(app: FastAPI):
92
+ # ๅฏๅŠจ๏ผšๅŽๅฐ็บฟ็จ‹ๅŠ ่ฝฝๆจกๅž‹ + ไฟๆดป็บฟ็จ‹
93
+ threading.Thread(target=load_models, daemon=True).start()
94
+ threading.Thread(target=keepalive_loop, daemon=True).start()
95
+ yield
96
+
97
+
98
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
99
+ # FastAPI App
100
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
101
+ app = FastAPI(
102
+ title="BGE API",
103
+ version="1.0.0",
104
+ lifespan=lifespan,
105
+ )
106
+
107
+ app.add_middleware(
108
+ CORSMiddleware,
109
+ allow_origins=["*"],
110
+ allow_methods=["*"],
111
+ allow_headers=["*"],
112
+ )
113
+
114
+
115
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
116
+ # ้‰ดๆƒ
117
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
118
+ security = HTTPBearer(auto_error=False)
119
+
120
+ def verify_api_key(
121
+ request: Request,
122
+ credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
123
+ ):
124
+ # ๆ”ฏๆŒ Bearer token ๅ’Œ ?api_key= ๅ‚ๆ•ฐไธค็งๆ–นๅผ
125
+ token = None
126
+ if credentials:
127
+ token = credentials.credentials
128
+ else:
129
+ token = request.query_params.get("api_key")
130
+
131
+ if token != API_KEY:
132
+ raise HTTPException(
133
+ status_code=401,
134
+ detail={"error": {"message": "Invalid API key", "type": "invalid_request_error"}},
135
+ )
136
+ return token
137
+
138
+
139
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
140
+ # Pydantic ๆจกๅž‹๏ผˆOpenAI ๅ…ผๅฎนๆ ผๅผ๏ผ‰
141
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
142
+ class EmbeddingRequest(BaseModel):
143
+ input: Union[str, List[str]]
144
+ model: str = "bge-m3:latest"
145
+ encoding_format: str = "float"
146
+
147
+ class RerankRequest(BaseModel):
148
+ model: str = "BAAI/bge-reranker-v2-m3"
149
+ query: str
150
+ documents: List[str]
151
+ top_n: Optional[int] = None
152
+ return_documents: bool = False
153
+
154
+ class EmbeddingObject(BaseModel):
155
+ object: str = "embedding"
156
+ index: int
157
+ embedding: List[float]
158
+
159
+ class Usage(BaseModel):
160
+ prompt_tokens: int
161
+ total_tokens: int
162
+
163
+ class EmbeddingResponse(BaseModel):
164
+ object: str = "list"
165
+ data: List[EmbeddingObject]
166
+ model: str
167
+ usage: Usage
168
+
169
+ class RerankResult(BaseModel):
170
+ index: int
171
+ relevance_score: float
172
+ document: Optional[Any] = None
173
+
174
+ class RerankResponse(BaseModel):
175
+ object: str = "list"
176
+ model: str
177
+ results: List[RerankResult]
178
+ usage: Usage
179
+
180
+
181
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
182
+ # ่ทฏ็”ฑ
183
+ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
184
+
185
+ @app.get("/", include_in_schema=False)
186
+ async def root():
187
+ """ๆ น็›ฎๅฝ•๏ผšๆ˜พ็คบๆจกๅž‹่ฟ่กŒ็Šถๆ€"""
188
+ uptime = int(time.time() - models["start_time"])
189
+ return JSONResponse({
190
+ "service": "BGE Embedding & Reranker API",
191
+ "version": "1.0.0",
192
+ "status": "running",
193
+ "uptime_sec": uptime,
194
+ "models": {
195
+ "embedding": {
196
+ "id": "bge-m3:latest",
197
+ "hf_id": EMBED_MODEL_ID,
198
+ "status": models["embed_status"],
199
+ },
200
+ "reranker": {
201
+ "id": "BAAI/bge-reranker-v2-m3",
202
+ "hf_id": RERANK_MODEL_ID,
203
+ "status": models["rerank_status"],
204
+ },
205
+ },
206
+ "endpoints": [
207
+ "GET /v1/models",
208
+ "POST /v1/embeddings",
209
+ "POST /v1/rerank",
210
+ "GET /health",
211
+ ],
212
+ })
213
+
214
+
215
+ @app.get("/health")
216
+ async def health():
217
+ return {
218
+ "status": "ok",
219
+ "embed_status": models["embed_status"],
220
+ "rerank_status": models["rerank_status"],
221
+ }
222
+
223
+
224
+ @app.get("/v1/models", dependencies=[Depends(verify_api_key)])
225
+ async def list_models():
226
+ """OpenAI ๅ…ผๅฎน็š„ๆจกๅž‹ๅˆ—่กจ"""
227
+ now = int(time.time())
228
+ return {
229
+ "object": "list",
230
+ "data": [
231
+ {
232
+ "id": "bge-m3:latest",
233
+ "object": "model",
234
+ "created": now,
235
+ "owned_by": "BAAI",
236
+ },
237
+ {
238
+ "id": "BAAI/bge-reranker-v2-m3",
239
+ "object": "model",
240
+ "created": now,
241
+ "owned_by": "BAAI",
242
+ },
243
+ ],
244
+ }
245
+
246
+
247
+ @app.post("/v1/embeddings", dependencies=[Depends(verify_api_key)])
248
+ async def create_embeddings(req: EmbeddingRequest):
249
+ if models["embed_status"] != "ready":
250
+ raise HTTPException(
251
+ status_code=503,
252
+ detail=f"Embedding model not ready: {models['embed_status']}",
253
+ )
254
+
255
+ texts = [req.input] if isinstance(req.input, str) else req.input
256
+ if not texts:
257
+ raise HTTPException(status_code=400, detail="input cannot be empty")
258
+
259
+ try:
260
+ result = models["embed"].encode(
261
+ texts,
262
+ batch_size=12,
263
+ max_length=8192,
264
+ return_dense=True,
265
+ return_sparse=False,
266
+ return_colbert_vecs=False,
267
+ )
268
+ dense_vecs = result["dense_vecs"] # numpy array
269
+ except Exception as e:
270
+ raise HTTPException(status_code=500, detail=str(e))
271
+
272
+ data = [
273
+ EmbeddingObject(index=i, embedding=vec.tolist())
274
+ for i, vec in enumerate(dense_vecs)
275
+ ]
276
+ total_tokens = sum(len(t.split()) for t in texts)
277
+
278
+ return EmbeddingResponse(
279
+ data=data,
280
+ model="bge-m3:latest",
281
+ usage=Usage(prompt_tokens=total_tokens, total_tokens=total_tokens),
282
+ )
283
+
284
+
285
+ @app.post("/v1/rerank", dependencies=[Depends(verify_api_key)])
286
+ async def rerank(req: RerankRequest):
287
+ if models["rerank_status"] != "ready":
288
+ raise HTTPException(
289
+ status_code=503,
290
+ detail=f"Reranker model not ready: {models['rerank_status']}",
291
+ )
292
+ if not req.documents:
293
+ raise HTTPException(status_code=400, detail="documents cannot be empty")
294
+
295
+ try:
296
+ pairs = [[req.query, doc] for doc in req.documents]
297
+ scores = models["reranker"].compute_score(pairs, normalize=True)
298
+ if isinstance(scores, float):
299
+ scores = [scores]
300
+ except Exception as e:
301
+ raise HTTPException(status_code=500, detail=str(e))
302
+
303
+ ranked = sorted(
304
+ enumerate(scores),
305
+ key=lambda x: x[1],
306
+ reverse=True,
307
+ )
308
+
309
+ top_n = req.top_n or len(ranked)
310
+ results = []
311
+ for rank_idx, (doc_idx, score) in enumerate(ranked[:top_n]):
312
+ item = RerankResult(
313
+ index=doc_idx,
314
+ relevance_score=float(score),
315
+ )
316
+ if req.return_documents:
317
+ item.document = {"text": req.documents[doc_idx]}
318
+ results.append(item)
319
+
320
+ total_tokens = len(req.query.split()) + sum(len(d.split()) for d in req.documents)
321
+
322
+ return RerankResponse(
323
+ model="BAAI/bge-reranker-v2-m3",
324
+ results=results,
325
+ usage=Usage(prompt_tokens=total_tokens, total_tokens=total_tokens),
326
+ )
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.111.0
2
+ uvicorn[standard]==0.30.1
3
+ FlagEmbedding==1.2.11
4
+ torch==2.3.1+cpu
5
+ transformers==4.41.2
6
+ huggingface_hub==0.23.4
7
+ pydantic==2.7.4
8
+ httpx==0.27.0
9
+ numpy==1.26.4