main.py 3.24 KB
Newer Older
1
from flask import Flask, request, Response, jsonify
Timothy J. Baek's avatar
Timothy J. Baek committed
2
3
4
5
6
7
8
from flask_cors import CORS


import requests
import json


9
10
from apps.web.models.users import Users
from constants import ERROR_MESSAGES
Timothy J. Baek's avatar
Timothy J. Baek committed
11
from utils.utils import extract_token_from_auth_header
12
from config import OLLAMA_API_BASE_URL, WEBUI_AUTH
Timothy J. Baek's avatar
Timothy J. Baek committed
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

app = Flask(__name__)
CORS(
    app
)  # Enable Cross-Origin Resource Sharing (CORS) to allow requests from different domains

# Define the target server URL
TARGET_SERVER_URL = OLLAMA_API_BASE_URL


@app.route("/", defaults={"path": ""}, methods=["GET", "POST", "PUT", "DELETE"])
@app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE"])
def proxy(path):
    # Combine the base URL of the target server with the requested path
    target_url = f"{TARGET_SERVER_URL}/{path}"
Timothy J. Baek's avatar
Timothy J. Baek committed
28
    print(path)
Timothy J. Baek's avatar
Timothy J. Baek committed
29
30
31
32
33

    # Get data from the original request
    data = request.get_data()
    headers = dict(request.headers)

Timothy J. Baek's avatar
Timothy J. Baek committed
34
    # Basic RBAC support
35
    if WEBUI_AUTH:
36
37
38
39
        if "Authorization" in headers:
            token = extract_token_from_auth_header(headers["Authorization"])
            user = Users.get_user_by_token(token)
            if user:
Timothy J. Baek's avatar
Timothy J. Baek committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
                # Only user and admin roles can access
                if user.role in ["user", "admin"]:
                    if path in ["pull", "delete", "push", "copy", "create"]:
                        # Only admin role can perform actions above
                        if user.role == "admin":
                            pass
                        else:
                            return (
                                jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}),
                                401,
                            )
                    else:
                        pass
                else:
                    return jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}), 401
55
56
57
58
59
60
61
            else:
                return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
        else:
            return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
    else:
        pass

62
63
    r = None

64
65
    try:
        # Make a request to the target server
66
        r = requests.request(
67
68
69
70
71
72
73
            method=request.method,
            url=target_url,
            data=data,
            headers=headers,
            stream=True,  # Enable streaming for server-sent events
        )

74
        r.raise_for_status()
75
76
77

        # Proxy the target server's response to the client
        def generate():
78
            for chunk in r.iter_content(chunk_size=8192):
79
80
                yield chunk

81
        response = Response(generate(), status=r.status_code)
82
83

        # Copy headers from the target server's response to the client's response
84
        for key, value in r.headers.items():
85
86
87
88
            response.headers[key] = value

        return response
    except Exception as e:
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
        error_detail = "Ollama WebUI: Server Connection Error"
        if r != None:
            res = r.json()
            if "error" in res:
                error_detail = f"Ollama: {res['error']}"
            print(res)

        return (
            jsonify(
                {
                    "detail": error_detail,
                    "message": str(e),
                }
            ),
            400,
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
105
106
107
108


if __name__ == "__main__":
    app.run(debug=True)