FreeLLMAPI / main.py
javaeeduke's picture
Update main.py
5519468 verified
Raw
History Blame
8.78 kB
from fastapi import FastAPI, HTTPException, Depends, Header
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse, HTMLResponse
import uvicorn
import os
import logging
import httpx
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(title="FreeLLMAPI")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ============================================================
# Provider Secrets
# ============================================================
PROVIDER_MAP = {
"GOOGLE_API_KEY": "google",
"GROQ_API_KEY": "groq",
"GITHUB_TOKEN": "github",
"OPENROUTER_API_KEY": "openrouter",
"MISTRAL_API_KEY": "mistral",
"TOGETHER_API_KEY": "together",
"NVIDIA_API_KEY": "nvidia",
"COHERE_API_KEY": "cohere",
"HF_TOKEN": "huggingface",
"CEREBRAS_API_KEY": "cerebras",
"SAMBANOVA_API_KEY": "sambanova",
"CLOUDFLARE_API_TOKEN": "cloudflare",
"ZHIPU_API_KEY": "zhipu",
}
PROVIDER_CONFIG = {
"google": {
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai",
"models": [
"gemini-2.0-flash",
"gemini-2.0-flash-lite",
"gemini-1.5-flash",
"gemini-1.5-pro",
],
},
"groq": {
"base_url": "https://api.groq.com/openai/v1",
"models": [
"llama-3.3-70b-versatile",
"llama-3.1-8b-instant",
"mixtral-8x7b-32768",
"gemma2-9b-it",
],
},
"github": {
"base_url": "https://models.inference.ai.azure.com",
"models": [
"gpt-4o",
"gpt-4o-mini",
"Phi-4",
"DeepSeek-R1",
],
},
"openrouter": {
"base_url": "https://openrouter.ai/api/v1",
"models": [
"deepseek/deepseek-r1:free",
"google/gemma-3-27b-it:free",
"meta-llama/llama-3.3-70b-instruct:free",
],
},
"mistral": {
"base_url": "https://api.mistral.ai/v1",
"models": [
"mistral-small-latest",
"mistral-large-latest",
],
},
"together": {
"base_url": "https://api.together.xyz/v1",
"models": [
"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
"deepseek-ai/DeepSeek-R1",
],
},
"nvidia": {
"base_url": "https://integrate.api.nvidia.com/v1",
"models": [
"meta/llama-3.1-70b-instruct",
"deepseek-ai/deepseek-r1",
],
},
"cohere": {
"base_url": "https://api.cohere.com/compatibility/v1",
"models": [
"command-r-plus",
"command-r",
],
},
"huggingface": {
"base_url": "https://huggingface.co/api/inference-proxy/together",
"models": [
"meta-llama/Llama-3.3-70B-Instruct",
"Qwen/Qwen2.5-72B-Instruct",
],
},
"cerebras": {
"base_url": "https://api.cerebras.ai/v1",
"models": [
"llama3.1-8b",
"llama3.3-70b",
],
},
"sambanova": {
"base_url": "https://api.sambanova.ai/v1",
"models": [
"Meta-Llama-3.1-405B-Instruct",
],
},
"cloudflare": {
"base_url": "https://api.cloudflare.com/client/v4/accounts/{}/ai/v1",
"models": [
"@cf/meta/llama-3.1-8b-instruct",
],
},
"zhipu": {
"base_url": "https://open.bigmodel.cn/api/paas/v4",
"models": [
"glm-4-flash",
"glm-4",
],
},
}
# ============================================================
# Load Config
# ============================================================
def load_config():
raw_keys = os.getenv("API_KEYS", "").strip()
api_keys = set(
k.strip()
for k in raw_keys.split(",")
if k.strip()
)
providers = {}
cf_account_id = os.getenv(
"CLOUDFLARE_ACCOUNT_ID",
""
)
for env_name, provider_name in PROVIDER_MAP.items():
key = os.getenv(env_name, "").strip()
if not key:
continue
cfg = PROVIDER_CONFIG[provider_name]
base_url = cfg["base_url"]
if provider_name == "cloudflare":
if cf_account_id:
base_url = base_url.format(cf_account_id)
providers[provider_name] = {
"api_key": key,
"base_url": base_url,
"models": cfg["models"],
}
logger.info(f"✅ Provider loaded: {provider_name}")
logger.info(
f"🚀 API Keys={len(api_keys)} Providers={len(providers)}"
)
return api_keys, providers
API_KEYS, PROVIDERS = load_config()
# ============================================================
# Auth
# ============================================================
def verify_api_key(
authorization: str = Header(...)
):
token = authorization.replace(
"Bearer ",
""
).strip()
if token not in API_KEYS:
raise HTTPException(
status_code=401,
detail="Invalid API key"
)
return token
# ============================================================
# Routes
# ============================================================
@app.get("/", response_class=HTMLResponse)
async def root():
return f"""
<html>
<body style="font-family:Arial;padding:40px">
<h1>🚀 FreeLLMAPI</h1>
<p>Status: ONLINE</p>
<p>Providers: {len(PROVIDERS)}</p>
<p>User Keys: {len(API_KEYS)}</p>
</body>
</html>
"""
@app.get("/health")
async def health():
return {
"status": "ok",
"providers": list(PROVIDERS.keys()),
"provider_count": len(PROVIDERS),
"user_keys": len(API_KEYS),
}
@app.get("/keys")
async def keys():
result = {}
for env_name, provider in PROVIDER_MAP.items():
result[provider] = bool(
os.getenv(env_name)
)
return {
"providers": result,
"provider_count": len(PROVIDERS),
"user_api_keys": len(API_KEYS),
}
@app.get("/debug")
async def debug():
return {
"providers_loaded": list(PROVIDERS.keys()),
"provider_count": len(PROVIDERS),
"user_api_keys": len(API_KEYS),
"total_models": sum(
len(x["models"])
for x in PROVIDERS.values()
),
}
@app.get("/v1/models")
async def models(
_: str = Depends(verify_api_key)
):
data = []
for provider in PROVIDERS.values():
for model in provider["models"]:
data.append({
"id": model,
"object": "model"
})
return {
"object": "list",
"data": data
}
@app.post("/v1/chat/completions")
async def chat(
body: dict,
_: str = Depends(verify_api_key)
):
model = body.get("model")
provider = None
for p in PROVIDERS.values():
if model in p["models"]:
provider = p
break
if not provider:
raise HTTPException(
status_code=404,
detail=f"Model not found: {model}"
)
target_url = (
provider["base_url"]
+ "/chat/completions"
)
headers = {
"Authorization":
f"Bearer {provider['api_key']}",
"Content-Type":
"application/json"
}
if provider["base_url"].startswith(
"https://openrouter.ai"
):
headers["HTTP-Referer"] = (
"https://huggingface.co"
)
headers["X-Title"] = (
"HF FreeLLMAPI"
)
if body.get("stream", False):
async def generate():
async with httpx.AsyncClient(
timeout=120
) as client:
async with client.stream(
"POST",
target_url,
headers=headers,
json=body,
) as response:
async for chunk in response.aiter_bytes():
yield chunk
return StreamingResponse(
generate(),
media_type="text/event-stream"
)
async with httpx.AsyncClient(
timeout=120
) as client:
response = await client.post(
target_url,
headers=headers,
json=body,
)
try:
return response.json()
except Exception:
return {
"raw": response.text
}
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0",
port=7860
)