Upload 5 files
Browse files
main.py
CHANGED
|
@@ -311,17 +311,30 @@ if not os.path.exists(model_path):
|
|
| 311 |
print(f"[Gateway] Đang tải {model_path} (khoảng 533MB)...")
|
| 312 |
model_path = hf_hub_download(repo_id="unsloth/Qwen3.5-0.8B-GGUF", filename="Qwen3.5-0.8B-Q4_K_M.gguf", local_dir=".")
|
| 313 |
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 325 |
|
| 326 |
import re
|
| 327 |
|
|
@@ -418,9 +431,33 @@ def read_root():
|
|
| 418 |
return {
|
| 419 |
"status": "online",
|
| 420 |
"service": "EvoNet B2B API Gateway",
|
| 421 |
-
"message": "Gateway is running. Send POST requests to /v1/chat/completions"
|
|
|
|
| 422 |
}
|
| 423 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 424 |
@app.post("/v1/chat/completions")
|
| 425 |
async def chat_completions(req: ChatCompletionRequest, request: Request, token: str = Depends(verify_b2b_token)):
|
| 426 |
if not req.messages:
|
|
@@ -471,11 +508,11 @@ async def chat_completions(req: ChatCompletionRequest, request: Request, token:
|
|
| 471 |
raise Exception("Swarm returned non-200 after retries")
|
| 472 |
except Exception as e:
|
| 473 |
print(f"[Gateway Routing] Lỗi từ DePIN Swarm ({e}), chuyển sang Fallback Local.")
|
| 474 |
-
result_text = f"
|
| 475 |
else:
|
| 476 |
# Step 2b: Fallback to Local Extreme Batching
|
| 477 |
print(f"[Gateway Routing] ➡️ DePIN bận/thiếu Node. Chuyển hướng xử lý tại Cụm Server Nội bộ.")
|
| 478 |
-
result_text = f"
|
| 479 |
|
| 480 |
# Step 3: Format OpenAI response
|
| 481 |
prompt_tokens = len(last_message.split())
|
|
|
|
| 311 |
print(f"[Gateway] Đang tải {model_path} (khoảng 533MB)...")
|
| 312 |
model_path = hf_hub_download(repo_id="unsloth/Qwen3.5-0.8B-GGUF", filename="Qwen3.5-0.8B-Q4_K_M.gguf", local_dir=".")
|
| 313 |
|
| 314 |
+
llm = None
|
| 315 |
+
|
| 316 |
+
def load_llm(lora_path=None):
|
| 317 |
+
global llm
|
| 318 |
+
try:
|
| 319 |
+
from llama_cpp import Llama
|
| 320 |
+
print(f"[Gateway] Đang nạp mô hình vào RAM (LoRA: {lora_path})...")
|
| 321 |
+
llm = Llama(
|
| 322 |
+
model_path=model_path,
|
| 323 |
+
lora_path=lora_path,
|
| 324 |
+
n_ctx=2048,
|
| 325 |
+
n_threads=2, # Tối ưu hóa cho máy 2 vCPU
|
| 326 |
+
verbose=False
|
| 327 |
+
)
|
| 328 |
+
print("[Gateway] Nạp mô hình thành công!")
|
| 329 |
+
except ImportError:
|
| 330 |
+
print("[Gateway] Cảnh báo: Chưa cài đặt llama-cpp-python. Fallback to mock.")
|
| 331 |
+
llm = None
|
| 332 |
+
except Exception as e:
|
| 333 |
+
print(f"[Gateway] Lỗi nạp mô hình: {e}")
|
| 334 |
+
llm = None
|
| 335 |
+
|
| 336 |
+
# Khởi tạo lần đầu
|
| 337 |
+
load_llm()
|
| 338 |
|
| 339 |
import re
|
| 340 |
|
|
|
|
| 431 |
return {
|
| 432 |
"status": "online",
|
| 433 |
"service": "EvoNet B2B API Gateway",
|
| 434 |
+
"message": "Gateway is running. Send POST requests to /v1/chat/completions",
|
| 435 |
+
"lora_supported": True
|
| 436 |
}
|
| 437 |
|
| 438 |
+
class LoadLoraRequest(BaseModel):
|
| 439 |
+
repo_id: Optional[str] = None
|
| 440 |
+
filename: str
|
| 441 |
+
|
| 442 |
+
@app.post("/v1/admin/load-lora")
|
| 443 |
+
async def api_load_lora(req: LoadLoraRequest, token: str = Depends(verify_b2b_token)):
|
| 444 |
+
"""API để nạp nóng Adapter LoRA từ Hugging Face (Dành cho Universal Agent)"""
|
| 445 |
+
try:
|
| 446 |
+
hf_token = os.environ.get("HF_ACCESS_TOKEN", None)
|
| 447 |
+
target_repo = req.repo_id if req.repo_id else os.environ.get("HF_LORA_REPO")
|
| 448 |
+
|
| 449 |
+
if not target_repo:
|
| 450 |
+
raise HTTPException(status_code=400, detail="Không có repo_id. Vui lòng truyền repo_id hoặc cấu hình HF_LORA_REPO")
|
| 451 |
+
|
| 452 |
+
print(f"[Gateway Admin] Yêu cầu nạp LoRA từ {target_repo}/{req.filename} (Private Mode: {bool(hf_token)})...")
|
| 453 |
+
lora_local_path = hf_hub_download(repo_id=target_repo, filename=req.filename, local_dir=".", token=hf_token)
|
| 454 |
+
# Chạy trong luồng riêng để không block API
|
| 455 |
+
await asyncio.to_thread(load_llm, lora_local_path)
|
| 456 |
+
return {"success": True, "message": f"Đã nạp thành công LoRA: {req.filename}"}
|
| 457 |
+
except Exception as e:
|
| 458 |
+
print(f"[Gateway Admin] Lỗi tải LoRA: {e}")
|
| 459 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 460 |
+
|
| 461 |
@app.post("/v1/chat/completions")
|
| 462 |
async def chat_completions(req: ChatCompletionRequest, request: Request, token: str = Depends(verify_b2b_token)):
|
| 463 |
if not req.messages:
|
|
|
|
| 508 |
raise Exception("Swarm returned non-200 after retries")
|
| 509 |
except Exception as e:
|
| 510 |
print(f"[Gateway Routing] Lỗi từ DePIN Swarm ({e}), chuyển sang Fallback Local.")
|
| 511 |
+
result_text = f"{await asyncio.to_thread(fallback_infer, messages_dicts)}"
|
| 512 |
else:
|
| 513 |
# Step 2b: Fallback to Local Extreme Batching
|
| 514 |
print(f"[Gateway Routing] ➡️ DePIN bận/thiếu Node. Chuyển hướng xử lý tại Cụm Server Nội bộ.")
|
| 515 |
+
result_text = f"{await asyncio.to_thread(fallback_infer, messages_dicts)}"
|
| 516 |
|
| 517 |
# Step 3: Format OpenAI response
|
| 518 |
prompt_tokens = len(last_message.split())
|