SHERWYNLUCIAN commited on
Commit
7d3f76e
·
verified ·
1 Parent(s): 83dd69b

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +12 -0
  2. main.py +196 -0
  3. requirements.txt +7 -0
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+ COPY requirements.txt .
5
+ RUN pip install --no-cache-dir -r requirements.txt
6
+
7
+ COPY . .
8
+
9
+ # Hugging Face exposes port 7860
10
+ EXPOSE 7860
11
+
12
+ CMD ["python", "main.py"]
main.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ import json
4
+ import time
5
+ import requests
6
+ import asyncio
7
+ import threading
8
+ from fastapi import FastAPI, Request, HTTPException, Depends
9
+ from fastapi.responses import JSONResponse
10
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
11
+ import uvicorn
12
+ from pydantic import BaseModel
13
+ from typing import List, Optional
14
+
15
+ try:
16
+ from vietnamese_ai.serving.batch_server import MayChuBatch # type: ignore
17
+ from vietnamese_ai.llm.vietnamese_llm import VietnameseLLM # type: ignore
18
+ except ImportError as e:
19
+ print(f"Error importing vietnamese-ai: {e}. Please run 'pip install vietnamese-ai'")
20
+ sys.exit(1)
21
+
22
+ app = FastAPI(
23
+ title="EvoNet Data Center - B2B API Gateway",
24
+ description="OpenAI-compatible Gateway routing traffic to DePIN or Local Extreme Batching",
25
+ version="2.0.0"
26
+ )
27
+
28
+ CENTER_URL = os.environ.get('CENTER_URL', 'https://evonet-ai.onrender.com')
29
+ # B2B_SECRET is now just a fallback if backend validation is unavailable
30
+ B2B_SECRET = os.environ.get('B2B_SECRET', 'evonet-b2b-partner-secret')
31
+
32
+ security = HTTPBearer()
33
+
34
+ print("[Gateway] Khởi tạo V-Neural Extreme JIT Engine...")
35
+ llm = VietnameseLLM(bac=3)
36
+ llm.huan_luyen(["EvoNet AI là mạng DePIN hàng đầu", "Continuous Batching giúp tăng tốc độ inference", "Mô hình ngôn ngữ lớn hoạt động cực nhanh"], so_vong=1)
37
+
38
+ def fallback_infer(prompt):
39
+ return llm.sinh_van_ban(prompt, do_dai=20)
40
+
41
+ def batch_predict(prompts):
42
+ """Wrapper cho Continuous Batching xử lý nhiều request cùng lúc"""
43
+ results = []
44
+ for p in prompts:
45
+ res = fallback_infer(p)
46
+ results.append(f"[Extreme JIT] {res}")
47
+ return results
48
+
49
+ batch_server = MayChuBatch(
50
+ mo_hinh=None,
51
+ ham_du_doan=batch_predict,
52
+ kich_thuoc_batch=32,
53
+ timeout_batch=0.05,
54
+ so_worker=4
55
+ )
56
+
57
+ def start_heartbeat(port):
58
+ while True:
59
+ try:
60
+ requests.post(f"{CENTER_URL}/api/v1/admin/datacenter/register", json={
61
+ "role": "Gateway",
62
+ "port": port
63
+ }, timeout=5)
64
+ except Exception:
65
+ pass
66
+ time.sleep(10)
67
+
68
+ @app.on_event("startup")
69
+ async def startup_event():
70
+ print("[Gateway] Bắt đầu Server Continuous Batching...")
71
+ batch_server.bat_dau()
72
+ port = int(os.environ.get("PORT", 7860))
73
+ threading.Thread(target=start_heartbeat, args=(port,), daemon=True).start()
74
+
75
+ @app.on_event("shutdown")
76
+ async def shutdown_event():
77
+ print("[Gateway] Tắt Server Continuous Batching...")
78
+ batch_server.dung()
79
+
80
+ # --- Schemas ---
81
+ class ChatMessage(BaseModel):
82
+ role: str
83
+ content: str
84
+
85
+ class ChatCompletionRequest(BaseModel):
86
+ model: str = "evonet-extreme-7b"
87
+ messages: List[ChatMessage]
88
+ temperature: Optional[float] = 0.7
89
+ max_tokens: Optional[int] = 512
90
+
91
+ # --- Dependency: Validate API Key via Center Backend ---
92
+ async def verify_b2b_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
93
+ token = credentials.credentials
94
+ # Fast path fallback for demo
95
+ if token == B2B_SECRET:
96
+ return token
97
+
98
+ # Validation against EvoNet Backend (Admin or API Key check)
99
+ try:
100
+ # Check if the API key is valid by asking the Center Backend
101
+ res = requests.get(f"{CENTER_URL}/api/v1/auth/validate-key", headers={"Authorization": f"Bearer {token}"}, timeout=2)
102
+ if res.status_code == 200:
103
+ return token
104
+ except Exception as e:
105
+ print(f"[Gateway] Validate Key Error: {e}")
106
+ pass
107
+
108
+ raise HTTPException(status_code=401, detail="Invalid API Key or Center Backend unavailable")
109
+
110
+ @app.get("/")
111
+ def read_root():
112
+ return {
113
+ "status": "online",
114
+ "service": "EvoNet B2B API Gateway",
115
+ "message": "Gateway is running. Send POST requests to /v1/chat/completions"
116
+ }
117
+
118
+ @app.post("/v1/chat/completions")
119
+ async def chat_completions(req: ChatCompletionRequest, request: Request, token: str = Depends(verify_b2b_token)):
120
+ if not req.messages:
121
+ raise HTTPException(status_code=400, detail="messages array cannot be empty")
122
+
123
+ last_message = req.messages[-1].content
124
+ print(f"[Gateway] B2B Request for model {req.model}")
125
+
126
+ active_nodes = 0
127
+ try:
128
+ # Step 1: Check swarm health
129
+ res = requests.get(f"{CENTER_URL}/api/v1/workers", timeout=2)
130
+ if res.status_code == 200:
131
+ workers = res.json().get('workers', [])
132
+ active_nodes = len(workers)
133
+ except Exception as e:
134
+ print(f"[Gateway] Center connection failed: {e}")
135
+
136
+ result_text = ""
137
+
138
+ if active_nodes > 0:
139
+ # Step 2a: Route to DePIN Swarm
140
+ print(f"[Gateway Routing] ➡️ Chuyển hướng tới DePIN Swarm ({active_nodes} nodes đang rảnh)")
141
+ try:
142
+ # We use a loop asyncio to not block FastAPI
143
+ loop = asyncio.get_event_loop()
144
+ def call_swarm():
145
+ return requests.post(
146
+ f"{CENTER_URL}/api/v1/swarm-inference",
147
+ json={"prompt": last_message, "max_tokens": req.max_tokens},
148
+ headers={"Authorization": f"Bearer {token}"},
149
+ timeout=15
150
+ )
151
+ res = await loop.run_in_executor(None, call_swarm)
152
+
153
+ if res.status_code == 200:
154
+ result_text = res.json().get('result', '')
155
+ else:
156
+ raise Exception("Swarm returned non-200")
157
+ except Exception as e:
158
+ print(f"[Gateway Routing] Lỗi từ DePIN Swarm ({e}), chuyển sang Fallback Local.")
159
+ result_text = batch_server.du_doan(last_message)
160
+ else:
161
+ # Step 2b: Fallback to Local Extreme Batching
162
+ print(f"[Gateway Routing] ➡️ DePIN bận/thiếu Node. Chuyển hướng xử lý tại Cụm Server Nội bộ.")
163
+ result_text = batch_server.du_doan(last_message)
164
+
165
+ # Step 3: Format OpenAI response
166
+ prompt_tokens = len(last_message.split())
167
+ completion_tokens = len(result_text.split())
168
+
169
+ return {
170
+ "id": f"chatcmpl-{int(time.time()*1000)}",
171
+ "object": "chat.completion",
172
+ "created": int(time.time()),
173
+ "model": req.model,
174
+ "choices": [{
175
+ "index": 0,
176
+ "message": {
177
+ "role": "assistant",
178
+ "content": result_text
179
+ },
180
+ "finish_reason": "stop"
181
+ }],
182
+ "usage": {
183
+ "prompt_tokens": prompt_tokens,
184
+ "completion_tokens": completion_tokens,
185
+ "total_tokens": prompt_tokens + completion_tokens
186
+ }
187
+ }
188
+
189
+ if __name__ == "__main__":
190
+ port = int(os.environ.get("PORT", 7860))
191
+ print("=================================================")
192
+ print("🏢 EvoNet Data Center - B2B API Gateway (FastAPI)")
193
+ print("⚡ V-Neural Extreme Continuous Batching ACTIVE")
194
+ print(f"✅ Running on port {port}")
195
+ print("=================================================")
196
+ uvicorn.run("main:app", host="0.0.0.0", port=port, log_level="info", workers=1)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ pydantic
4
+ requests
5
+ numpy
6
+ torch
7
+ vietnamese-ai