File size: 6,378 Bytes
3efb61d df1c78b 3efb61d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | import os
import json
import time
import requests
from flask import Flask, request, jsonify, Response, stream_with_context
app = Flask(__name__)
ENDPOINT_URL = "https://o1zwshreete15x04.us-east-1.aws.endpoints.huggingface.cloud"
HF_TOKEN = os.getenv("HF_TOKEN", "")
CHUNK_SIZE = int(os.getenv("CHUNK_SIZE", "2")) # chars per stream chunk
CHUNK_DELAY = float(os.getenv("CHUNK_DELAY", "0.012")) # seconds between chunks
def _headers():
return {
"Accept": "application/json",
"Authorization": f"Bearer {HF_TOKEN}",
"Content-Type": "application/json",
}
@app.route("/health", methods=["GET"])
def health():
"""
Lightweight health check β just pings the endpoint with a tiny prompt.
"""
if not ENDPOINT_URL or not HF_TOKEN:
return jsonify({
"status": "unhealthy",
"error": "ENDPOINT_URL or HF_TOKEN env var not set"
}), 503
try:
resp = requests.post(
ENDPOINT_URL,
headers=_headers(),
json={
"inputs": [{"role": "user", "content": "Hi"}],
"parameters": {
"max_new_tokens": 5,
"temperature": 0.1,
"do_sample": False,
}
},
timeout=20,
)
if resp.status_code == 200:
return jsonify({"status": "healthy", "code": 200})
return jsonify({
"status": "unhealthy",
"code": resp.status_code,
"error": resp.text[:300],
}), 503
except requests.exceptions.Timeout:
return jsonify({"status": "unhealthy", "error": "Endpoint timed out"}), 503
except Exception as e:
return jsonify({"status": "unhealthy", "error": str(e)}), 503
@app.route("/chat", methods=["POST"])
def chat():
"""
Accepts:
{
"messages": [{role, content}, ...],
"max_tokens": 512,
"temperature": 0.7,
"top_p": 0.9,
"do_sample": true,
"stream": true <-- if true, SSE stream back to caller
}
"""
data = request.get_json(silent=True) or {}
messages = data.get("messages", [])
max_tokens = int(data.get("max_tokens", 512))
temperature = float(data.get("temperature", 0.7))
top_p = float(data.get("top_p", 0.9))
do_sample = bool(data.get("do_sample", temperature > 0))
stream = bool(data.get("stream", True))
if not messages:
return jsonify({"error": "messages array required"}), 400
# Build payload for your custom handler
payload = {
"inputs": [{"role": m["role"], "content": m["content"]} for m in messages],
"parameters": {
"max_new_tokens": max_tokens,
"temperature": temperature,
"top_p": top_p,
"do_sample": do_sample,
}
}
# ββ Non-streaming βββββββββββββββββββββββββββββββββββββββββ
if not stream:
try:
resp = requests.post(
ENDPOINT_URL,
headers=_headers(),
json=payload,
timeout=90,
)
resp.raise_for_status()
result = resp.json()
text = _extract_text(result)
return jsonify({"generated_text": text, "ok": True})
except Exception as e:
return jsonify({"error": str(e)}), 500
# ββ Streaming βββββββββββββββββββββββββββββββββββββββββββββ
def generate():
try:
resp = requests.post(
ENDPOINT_URL,
headers=_headers(),
json=payload,
timeout=90,
)
resp.raise_for_status()
result = resp.json()
full_text = _extract_text(result)
if not full_text:
yield _sse({"error": "Empty response from model"})
return
# ββ Smooth streaming in small character chunks ββββ
# We buffer into "word-aware" chunks so words don't
# get split mid-character in a jarring way.
buffer = ""
for char in full_text:
buffer += char
# Flush on punctuation/spaces for natural rhythm
should_flush = (
len(buffer) >= CHUNK_SIZE or
char in (' ', '\n', '.', ',', '!', '?', ':', ';')
)
if should_flush and buffer:
yield _sse({"token": buffer})
buffer = ""
time.sleep(CHUNK_DELAY)
# Flush any remaining buffer
if buffer:
yield _sse({"token": buffer})
yield "data: [DONE]\n\n"
except requests.exceptions.Timeout:
yield _sse({"error": "Endpoint timed out β try again"})
except requests.exceptions.HTTPError as e:
yield _sse({"error": f"Endpoint error {e.response.status_code}: {e.response.text[:200]}"})
except Exception as e:
yield _sse({"error": str(e)})
return Response(
stream_with_context(generate()),
content_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"X-Accel-Buffering": "no",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": "*",
}
)
@app.route("/", methods=["GET"])
def root():
return jsonify({
"name": "SmilyAI Proxy",
"status": "running",
"routes": ["/health", "/chat"],
"model": "SmilyAI 1.2B ChatML",
})
def _extract_text(result):
"""Pull generated_text out of whatever shape the endpoint returns."""
if isinstance(result, list) and len(result) > 0:
return result[0].get("generated_text", "")
if isinstance(result, dict):
return result.get("generated_text", "")
return str(result)
def _sse(obj):
"""Format a dict as an SSE data line."""
return f"data: {json.dumps(obj)}\n\n"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860, debug=False) |