beryl-chat-api / app.py
AIBRUH
Use featherless-ai provider via HF Router — avoids dead api-inference DNS
419498a
Raw
History Blame Contribute Delete
3.22 kB
"""
Beryl Chat API — FastAPI raw inference proxy (Docker Space)
Calls api-inference.huggingface.co directly (resolves inside HF network).
POST /run/predict → { data: [messages_json, model_key] }
"""
import os, json, requests
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
HF_TOKEN = os.environ.get("HF_TOKEN", "")
# Featherless AI provider via HF Router — resolves everywhere, supports Qwen/Mistral
HF_API = "https://router.huggingface.co/featherless-ai/v1/chat/completions"
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}", "Content-Type": "application/json"}
MODELS = {
"qwen": "Qwen/Qwen2.5-72B-Instruct",
"qwen7b": "Qwen/Qwen2.5-7B-Instruct",
"glm": "Qwen/Qwen2.5-7B-Instruct",
"hermes": "NousResearch/Hermes-3-Llama-3.1-8B",
"auto": "Qwen/Qwen2.5-7B-Instruct",
}
EMOTION_KW = ["feel","lonely","sad","love","companion","miss",
"emotional","relationship","heart","care","hurt"]
app = FastAPI(title="Beryl Chat API")
def route_model(messages: list, model_key: str) -> str:
if model_key and model_key not in ("auto", ""):
return MODELS.get(model_key, MODELS["auto"])
last = (messages[-1].get("content","") if messages else "").lower()
return MODELS["glm"] if any(k in last for k in EMOTION_KW) else MODELS["auto"]
def do_chat(messages: list, model_key: str) -> dict:
model = route_model(messages, model_key)
payload = {
"model": model,
"messages": messages,
"max_tokens": 600,
"temperature": 0.78,
"stream": False,
}
r = requests.post(HF_API, headers=HEADERS, json=payload, timeout=30)
if r.status_code == 200:
data = r.json()
return {
"response": data["choices"][0]["message"]["content"],
"model": model.split("/")[-1],
"ok": True,
}
# Fallback: try Qwen2.5-7B if primary model unavailable/quota
if r.status_code in (429, 503, 400) and model != MODELS["qwen7b"]:
payload["model"] = MODELS["qwen7b"]
r2 = requests.post(HF_API, headers=HEADERS, json=payload, timeout=30)
if r2.status_code == 200:
data2 = r2.json()
return {
"response": data2["choices"][0]["message"]["content"],
"model": "Qwen2.5-7B-Instruct",
"ok": True,
}
return {"ok": False, "error": f"HTTP {r.status_code}: {r.text[:200]}", "response": ""}
@app.get("/health")
def health():
return {"ok": True, "version": "1.0.0", "service": "beryl-chat-api"}
@app.post("/predict")
@app.post("/run/predict")
async def predict(request: Request):
try:
body = await request.json()
data = body.get("data", [])
messages_json = data[0] if len(data) > 0 else "[]"
model_key = data[1] if len(data) > 1 else "auto"
messages = json.loads(messages_json)
result = do_chat(messages, model_key)
return JSONResponse({"data": [json.dumps(result)]})
except Exception as e:
err = json.dumps({"ok": False, "error": str(e), "response": ""})
return JSONResponse({"data": [err]}, status_code=200)