File size: 3,348 Bytes
dcdc87a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4141a22
dcdc87a
 
 
 
 
 
4141a22
 
 
 
 
dcdc87a
 
 
 
 
4141a22
 
 
 
 
 
 
dcdc87a
4141a22
 
 
 
 
 
 
 
dcdc87a
4141a22
 
 
 
 
 
 
 
 
 
 
 
 
dcdc87a
 
 
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
#!/usr/bin/env python3
"""
SmilyAI Proxy β€” runs on a HF Space.
Forwards authenticated requests to a private HF Inference Endpoint.
Exists because PythonAnywhere's free tier can't reach arbitrary outbound
hosts, but *.hf.space IS whitelisted.
"""

import os
import json
import requests
from flask import Flask, request, Response, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

# ── Config (set these as SECRETS in the Space settings, not hardcoded!) ──────
TARGET_BASE_URL = os.environ.get("TARGET_BASE_URL", "").rstrip("/")
HF_TOKEN = os.environ.get("HF_TOKEN", "")
PROXY_SECRET = os.environ.get("PROXY_SECRET", "")  # shared secret w/ your Flask app

if not TARGET_BASE_URL or not HF_TOKEN or not PROXY_SECRET:
    print("⚠ WARNING: TARGET_BASE_URL / HF_TOKEN / PROXY_SECRET not fully set!")


def check_auth(req) -> bool:
    key = req.headers.get("X-Proxy-Key", "")
    return PROXY_SECRET and key == PROXY_SECRET


@app.route("/", methods=["GET"])
def health():
    return jsonify({"status": "ok", "service": "smilyai-proxy"})


@app.route("/v1/chat/completions", methods=["POST"])
def chat_completions():
    if not check_auth(request):
        return jsonify({"error": "unauthorized"}), 401

    try:
        payload = request.get_json(force=True)
    except Exception:
        return jsonify({"error": "invalid json body"}), 400

    is_stream = bool(payload.get("stream", False))
    headers = {
        "Authorization": f"Bearer {HF_TOKEN}",
        "Content-Type": "application/json; charset=utf-8",  # ← add charset here
    }
    url = f"{TARGET_BASE_URL}/chat/completions"

    if not is_stream:
        try:
            r = requests.post(url, headers=headers, json=payload, timeout=120)
            return Response(
                r.content,
                status=r.status_code,
                content_type="application/json; charset=utf-8"  # ← fix here too
            )
        except Exception as e:
            return jsonify({"error": str(e)}), 502

    def generate():
        try:
            with requests.post(
                url, headers=headers, json=payload,
                stream=True, timeout=120
            ) as r:
                # ← KEY FIX: iter_lines with encoding="utf-8" explicitly
                for raw_line in r.iter_lines(decode_unicode=False):
                    if raw_line is None:
                        continue
                    # decode bytes as utf-8 explicitly
                    if isinstance(raw_line, bytes):
                        line = raw_line.decode("utf-8", errors="replace")
                    else:
                        line = raw_line
                    if not line:
                        continue
                    yield (line + "\n\n").encode("utf-8")
        except Exception as e:
            err = json.dumps({"error": str(e)}, ensure_ascii=False)
            yield f"data: {err}\n\n".encode("utf-8")
            yield b"data: [DONE]\n\n"

    return Response(
        generate(),
        content_type="text/event-stream; charset=utf-8",  # ← charset here
        headers={
            "Cache-Control": "no-cache",
            "X-Accel-Buffering": "no",
            "Transfer-Encoding": "chunked",
        }
    )

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))