Spaces:
Runtime error
Runtime error
Update main.py
Browse files
main.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
from fastapi import FastAPI, HTTPException, Depends, Header
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
| 3 |
import uvicorn
|
| 4 |
import os
|
| 5 |
import logging
|
|
@@ -21,7 +22,6 @@ app.add_middleware(
|
|
| 21 |
# ่ฏปๅๅ้กน็ฎๅบๅฎๅฝๅ็ Secrets
|
| 22 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 23 |
|
| 24 |
-
# ๅ้กน็ฎ็ Provider Key ๆ ๅฐ่กจ
|
| 25 |
PROVIDER_MAP = {
|
| 26 |
"GOOGLE_API_KEY": "google",
|
| 27 |
"GROQ_API_KEY": "groq",
|
|
@@ -38,7 +38,6 @@ PROVIDER_MAP = {
|
|
| 38 |
"ZHIPU_API_KEY": "zhipu",
|
| 39 |
}
|
| 40 |
|
| 41 |
-
# Provider ๅฏนๅบ็ base_url ๅๆฏๆ็ๆจกๅ
|
| 42 |
PROVIDER_CONFIG = {
|
| 43 |
"google": {
|
| 44 |
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
@@ -134,29 +133,34 @@ PROVIDER_CONFIG = {
|
|
| 134 |
|
| 135 |
def load_config():
|
| 136 |
"""ไป็ฏๅขๅ้่ฏปๅๆๆ้
็ฝฎ"""
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
raw_keys = os.getenv("API_KEYS", "")
|
| 140 |
api_keys = set(k.strip() for k in raw_keys.split(",") if k.strip())
|
| 141 |
|
| 142 |
# โโ ่ฏปๅ Provider Keys โโ
|
| 143 |
providers = {}
|
|
|
|
|
|
|
| 144 |
for env_name, provider_name in PROVIDER_MAP.items():
|
| 145 |
key_value = os.getenv(env_name, "").strip()
|
| 146 |
if not key_value:
|
| 147 |
-
continue
|
| 148 |
|
| 149 |
cfg = PROVIDER_CONFIG.get(provider_name, {})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
providers[provider_name] = {
|
| 151 |
"api_key": key_value,
|
| 152 |
-
"base_url":
|
| 153 |
"models": cfg.get("models", []),
|
| 154 |
}
|
| 155 |
logger.info(f"โ
ๅ ่ฝฝ Provider: {provider_name}")
|
| 156 |
|
| 157 |
-
logger.info(f"
|
| 158 |
-
logger.info(f"โ
ๅ ่ฝฝไบ {len(providers)} ไธช Provider: {list(providers.keys())}")
|
| 159 |
-
|
| 160 |
return api_keys, providers
|
| 161 |
|
| 162 |
|
|
@@ -173,11 +177,27 @@ def verify_api_key(authorization: str = Header(...)):
|
|
| 173 |
return token
|
| 174 |
|
| 175 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 176 |
-
# ่ทฏ็ฑ
|
| 177 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
@app.get("/health")
|
| 180 |
async def health():
|
|
|
|
| 181 |
return {
|
| 182 |
"status": "ok",
|
| 183 |
"keys": len(API_KEYS),
|
|
@@ -195,11 +215,8 @@ async def list_models(_: str = Depends(verify_api_key)):
|
|
| 195 |
|
| 196 |
|
| 197 |
@app.post("/v1/chat/completions")
|
| 198 |
-
async def chat_completions(
|
| 199 |
-
|
| 200 |
-
_: str = Depends(verify_api_key)
|
| 201 |
-
):
|
| 202 |
-
model = body.get("model", "")
|
| 203 |
provider = None
|
| 204 |
|
| 205 |
for p_cfg in PROVIDERS.values():
|
|
@@ -213,18 +230,25 @@ async def chat_completions(
|
|
| 213 |
detail=f"ๆฒกๆ Provider ๆฏๆๆจกๅ: {model}"
|
| 214 |
)
|
| 215 |
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
return resp.json()
|
| 223 |
|
|
|
|
|
|
|
| 224 |
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
|
| 229 |
|
| 230 |
if __name__ == "__main__":
|
|
|
|
| 1 |
from fastapi import FastAPI, HTTPException, Depends, Header
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
+
from fastapi.responses import StreamingResponse, HTMLResponse
|
| 4 |
import uvicorn
|
| 5 |
import os
|
| 6 |
import logging
|
|
|
|
| 22 |
# ่ฏปๅๅ้กน็ฎๅบๅฎๅฝๅ็ Secrets
|
| 23 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 24 |
|
|
|
|
| 25 |
PROVIDER_MAP = {
|
| 26 |
"GOOGLE_API_KEY": "google",
|
| 27 |
"GROQ_API_KEY": "groq",
|
|
|
|
| 38 |
"ZHIPU_API_KEY": "zhipu",
|
| 39 |
}
|
| 40 |
|
|
|
|
| 41 |
PROVIDER_CONFIG = {
|
| 42 |
"google": {
|
| 43 |
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
|
|
| 133 |
|
| 134 |
def load_config():
|
| 135 |
"""ไป็ฏๅขๅ้่ฏปๅๆๆ้
็ฝฎ"""
|
| 136 |
+
# โโ ่ฏปๅ็จๆท API Keys โโ
|
| 137 |
+
raw_keys = os.getenv("API_KEYS", "").strip()
|
|
|
|
| 138 |
api_keys = set(k.strip() for k in raw_keys.split(",") if k.strip())
|
| 139 |
|
| 140 |
# โโ ่ฏปๅ Provider Keys โโ
|
| 141 |
providers = {}
|
| 142 |
+
cf_account = os.getenv("CLOUDFLARE_ACCOUNT_ID", "default_id")
|
| 143 |
+
|
| 144 |
for env_name, provider_name in PROVIDER_MAP.items():
|
| 145 |
key_value = os.getenv(env_name, "").strip()
|
| 146 |
if not key_value:
|
| 147 |
+
continue
|
| 148 |
|
| 149 |
cfg = PROVIDER_CONFIG.get(provider_name, {})
|
| 150 |
+
base_url = cfg.get("base_url", "")
|
| 151 |
+
|
| 152 |
+
# ๅฎๅ
จไฟฎๅค๏ผๅจๆ็ป่ฃ
Cloudflare ็่ดฆๆท ID ่ทฏๅพ
|
| 153 |
+
if provider_name == "cloudflare" and "{}" in base_url:
|
| 154 |
+
base_url = base_url.format(cf_account)
|
| 155 |
+
|
| 156 |
providers[provider_name] = {
|
| 157 |
"api_key": key_value,
|
| 158 |
+
"base_url": base_url,
|
| 159 |
"models": cfg.get("models", []),
|
| 160 |
}
|
| 161 |
logger.info(f"โ
ๅ ่ฝฝ Provider: {provider_name}")
|
| 162 |
|
| 163 |
+
logger.info(f"๐ ๅ ่ฝฝๆๅ๏ผ็จๆทๆๆ Key ๆฐ้: {len(api_keys)} | ้้็ฝๅ
ณๆฐ้: {len(providers)}")
|
|
|
|
|
|
|
| 164 |
return api_keys, providers
|
| 165 |
|
| 166 |
|
|
|
|
| 177 |
return token
|
| 178 |
|
| 179 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 180 |
+
# ่ทฏ็ฑๆ ๅฐ
|
| 181 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 182 |
|
| 183 |
+
@app.get("/", response_class=HTMLResponse)
|
| 184 |
+
async def index():
|
| 185 |
+
return """
|
| 186 |
+
<html>
|
| 187 |
+
<head><title>FreeLLMAPI Gateway</title></head>
|
| 188 |
+
<body style="font-family: Arial, sans-serif; text-align: center; margin-top: 100px; background-color: #f4f4f9;">
|
| 189 |
+
<h1 style="color: #4f46e5;">๐ FreeLLMAPI ็ฏๅขๅ้ๆ้็</h1>
|
| 190 |
+
<p style="color: #6b7280;">ไบ็ซฏ่ฝป้ๅๆ ๆไน
ๅ่ฝฌๅ็ฝๅ
ณ่ฟ่กไธญ...</p>
|
| 191 |
+
<div style="margin-top: 20px;">
|
| 192 |
+
<span style="background-color: #10b981; color: white; padding: 6px 16px; border-radius: 20px; font-size: 0.9em; font-weight: bold;">STATUS: ONLINE</span>
|
| 193 |
+
</div>
|
| 194 |
+
</body>
|
| 195 |
+
</html>
|
| 196 |
+
"""
|
| 197 |
+
|
| 198 |
@app.get("/health")
|
| 199 |
async def health():
|
| 200 |
+
# ๅฎ็พๅๅนถๅ็ๆฃๆฅ่ทฏ็ฑ
|
| 201 |
return {
|
| 202 |
"status": "ok",
|
| 203 |
"keys": len(API_KEYS),
|
|
|
|
| 215 |
|
| 216 |
|
| 217 |
@app.post("/v1/chat/completions")
|
| 218 |
+
async def chat_completions(body: dict, _: str = Depends(verify_api_key)):
|
| 219 |
+
model = body.get("model", "")
|
|
|
|
|
|
|
|
|
|
| 220 |
provider = None
|
| 221 |
|
| 222 |
for p_cfg in PROVIDERS.values():
|
|
|
|
| 230 |
detail=f"ๆฒกๆ Provider ๆฏๆๆจกๅ: {model}"
|
| 231 |
)
|
| 232 |
|
| 233 |
+
# ๅฎ็พๆฏๆๆตๅผ่พๅบไธๆฎ้ๅๅบ็ๆ ธๅฟไธญ่ฝฌ้ป่พ
|
| 234 |
+
async def stream_generator(target_url, headers, payload):
|
| 235 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
| 236 |
+
async with client.stream("POST", target_url, headers=headers, json=payload) as response:
|
| 237 |
+
async for chunk in response.aiter_bytes():
|
| 238 |
+
yield chunk
|
|
|
|
| 239 |
|
| 240 |
+
target_url = f"{provider['base_url']}/chat/completions"
|
| 241 |
+
headers = {"Authorization": f"Bearer {provider['api_key']}"}
|
| 242 |
|
| 243 |
+
if body.get("stream", False):
|
| 244 |
+
return StreamingResponse(
|
| 245 |
+
stream_generator(target_url, headers, body),
|
| 246 |
+
media_type="text/event-stream"
|
| 247 |
+
)
|
| 248 |
+
else:
|
| 249 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
| 250 |
+
resp = await client.post(target_url, headers=headers, json=body)
|
| 251 |
+
return resp.json()
|
| 252 |
|
| 253 |
|
| 254 |
if __name__ == "__main__":
|