AIBRUH commited on
Commit
d1ceaf4
·
1 Parent(s): 21d3dd8

Switch to FastAPI Docker Space — no Gradio/pydub Python 3.13 issue

Browse files
Files changed (3) hide show
  1. Dockerfile +11 -0
  2. README.md +3 -5
  3. app.py +41 -60
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN pip install --no-cache-dir fastapi uvicorn huggingface_hub
6
+
7
+ COPY app.py .
8
+
9
+ EXPOSE 7860
10
+
11
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -3,21 +3,19 @@ title: Beryl Chat API
3
  emoji: 🤖
4
  colorFrom: yellow
5
  colorTo: gray
6
- sdk: gradio
7
- sdk_version: 5.0.0
8
- app_file: app.py
9
  pinned: true
10
  license: mit
11
  ---
12
 
13
  # Beryl Chat API
14
 
15
- Raw-mode Gradio inference proxy for Beryl Desktop.
16
 
17
  ## API Usage
18
 
19
  ```
20
- POST /api/predict
21
  Content-Type: application/json
22
 
23
  {
 
3
  emoji: 🤖
4
  colorFrom: yellow
5
  colorTo: gray
6
+ sdk: docker
 
 
7
  pinned: true
8
  license: mit
9
  ---
10
 
11
  # Beryl Chat API
12
 
13
+ Raw FastAPI inference proxy for Beryl Desktop.
14
 
15
  ## API Usage
16
 
17
  ```
18
+ POST /predict
19
  Content-Type: application/json
20
 
21
  {
app.py CHANGED
@@ -1,10 +1,12 @@
1
  """
2
- Beryl Chat API — Gradio raw-mode proxy Space
3
- Hosted at: AIBRUH/beryl-chat-api
4
- Routes: POST /api/predict → { data: [messages_json, model_key] }
5
- Returns: { data: [response_text] }
6
  """
7
- import os, json, gradio as gr
 
 
8
  from huggingface_hub import InferenceClient
9
 
10
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
@@ -17,69 +19,48 @@ MODELS = {
17
  "auto": "Qwen/Qwen2.5-7B-Instruct",
18
  }
19
 
20
- EMOTION_KW = ["feel","lonely","sad","love","companion","miss","emotional","relationship"]
 
21
 
22
- def route_model(messages_list, model_key):
23
- if model_key and model_key != "auto":
24
- return MODELS.get(model_key, MODELS["auto"])
25
- last = (messages_list[-1].get("content","") if messages_list else "").lower()
26
- if any(k in last for k in EMOTION_KW):
27
- return MODELS["glm"]
28
- return MODELS["qwen"]
29
 
30
- def chat(messages_json: str, model_key: str = "auto") -> str:
31
- """Raw inference endpoint. Called via Gradio HTTP API."""
32
- try:
33
- messages = json.loads(messages_json)
34
- if not isinstance(messages, list):
35
- return json.dumps({"error": "messages must be a JSON array"})
36
 
37
- model = route_model(messages, model_key.strip() if model_key else "auto")
 
 
 
 
38
 
39
- client = InferenceClient(
40
- provider="hf-inference",
41
- api_key=HF_TOKEN,
42
- )
43
 
44
- result = client.chat_completion(
45
- model=model,
46
- messages=messages,
47
- max_tokens=600,
48
- temperature=0.78,
49
- )
50
- response = result.choices[0].message.content
51
- return json.dumps({
52
- "response": response,
53
- "model": model.split("/")[-1],
54
- "ok": True,
55
- })
56
 
57
- except Exception as e:
58
- # Return error as JSON so caller can handle gracefully
59
- return json.dumps({"ok": False, "error": str(e), "response": ""})
60
 
 
 
 
61
 
62
- def health() -> str:
63
- return json.dumps({"ok": True, "version": "1.0.0", "service": "beryl-chat-api"})
64
 
 
 
 
 
 
 
 
 
65
 
66
- # ── Raw Gradio interface — NO visual components used ──────────────────────────
67
- # gr.Interface exposes /api/predict automatically
68
- with gr.Blocks(title="Beryl Chat API") as demo:
69
- # Minimal UI just to satisfy HF Space requirements
70
- gr.Markdown("## Beryl Chat API\nRaw inference proxy. Call `/api/predict` directly.")
71
- with gr.Row(visible=False):
72
- msg_in = gr.Textbox(label="messages_json")
73
- model_in = gr.Textbox(label="model_key", value="auto")
74
- out = gr.Textbox(label="response_json")
75
- btn = gr.Button("Run")
76
- btn.click(fn=chat, inputs=[msg_in, model_in], outputs=out)
77
-
78
- # Also expose health
79
- with gr.Row(visible=False):
80
- health_out = gr.Textbox(label="health")
81
- health_btn = gr.Button("health")
82
- health_btn.click(fn=health, inputs=[], outputs=health_out)
83
 
84
- if __name__ == "__main__":
85
- demo.launch(server_name="0.0.0.0", server_port=7860, show_api=True)
 
 
1
  """
2
+ Beryl Chat API — FastAPI raw inference proxy
3
+ Hosted at: AIBRUH/beryl-chat-api (Docker Space)
4
+ POST /predict → { data: [messages_json, model_key] }
5
+ POST /run/predict → same (Gradio-compat alias)
6
  """
7
+ import os, json
8
+ from fastapi import FastAPI, Request
9
+ from fastapi.responses import JSONResponse
10
  from huggingface_hub import InferenceClient
11
 
12
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
 
19
  "auto": "Qwen/Qwen2.5-7B-Instruct",
20
  }
21
 
22
+ EMOTION_KW = ["feel","lonely","sad","love","companion","miss",
23
+ "emotional","relationship","heart","care","hurt"]
24
 
25
+ app = FastAPI(title="Beryl Chat API")
 
 
 
 
 
 
26
 
 
 
 
 
 
 
27
 
28
+ def route_model(messages: list, model_key: str) -> str:
29
+ if model_key and model_key not in ("auto", ""):
30
+ return MODELS.get(model_key, MODELS["auto"])
31
+ last = (messages[-1].get("content","") if messages else "").lower()
32
+ return MODELS["glm"] if any(k in last for k in EMOTION_KW) else MODELS["qwen"]
33
 
 
 
 
 
34
 
35
+ def do_chat(messages: list, model_key: str) -> dict:
36
+ model = route_model(messages, model_key)
37
+ client = InferenceClient(provider="hf-inference", api_key=HF_TOKEN)
38
+ result = client.chat_completion(
39
+ model=model, messages=messages,
40
+ max_tokens=600, temperature=0.78,
41
+ )
42
+ return {"response": result.choices[0].message.content,
43
+ "model": model.split("/")[-1], "ok": True}
 
 
 
44
 
 
 
 
45
 
46
+ @app.get("/health")
47
+ def health():
48
+ return {"ok": True, "version": "1.0.0", "service": "beryl-chat-api"}
49
 
 
 
50
 
51
+ @app.post("/predict")
52
+ @app.post("/run/predict") # Gradio-compat alias
53
+ async def predict(request: Request):
54
+ try:
55
+ body = await request.json()
56
+ data = body.get("data", [])
57
+ messages_json = data[0] if len(data) > 0 else "[]"
58
+ model_key = data[1] if len(data) > 1 else "auto"
59
 
60
+ messages = json.loads(messages_json)
61
+ result = do_chat(messages, model_key)
62
+ return JSONResponse({"data": [json.dumps(result)]})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
+ except Exception as e:
65
+ err = json.dumps({"ok": False, "error": str(e), "response": ""})
66
+ return JSONResponse({"data": [err]}, status_code=200)