2024-01-04 21:06:31 +00:00
|
|
|
from flask import Flask, request, Response, jsonify
|
|
|
|
from flask_cors import CORS
|
|
|
|
|
|
|
|
import requests
|
|
|
|
import json
|
|
|
|
|
|
|
|
from apps.web.models.users import Users
|
|
|
|
from constants import ERROR_MESSAGES
|
|
|
|
from utils.utils import decode_token
|
|
|
|
from config import OLLAMA_API_BASE_URL, WEBUI_AUTH
|
|
|
|
|
|
|
|
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("/url", methods=["GET"])
|
|
|
|
def get_ollama_api_url():
|
|
|
|
headers = dict(request.headers)
|
|
|
|
if "Authorization" in headers:
|
|
|
|
_, credentials = headers["Authorization"].split()
|
|
|
|
token_data = decode_token(credentials)
|
|
|
|
if token_data is None or "email" not in token_data:
|
|
|
|
return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
|
|
|
|
|
|
|
|
user = Users.get_user_by_email(token_data["email"])
|
|
|
|
if user and user.role == "admin":
|
|
|
|
return (
|
|
|
|
jsonify({"OLLAMA_API_BASE_URL": TARGET_SERVER_URL}),
|
|
|
|
200,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return (
|
|
|
|
jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}),
|
|
|
|
401,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return (
|
|
|
|
jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}),
|
|
|
|
401,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/url/update", methods=["POST"])
|
|
|
|
def update_ollama_api_url():
|
|
|
|
headers = dict(request.headers)
|
|
|
|
data = request.get_json(force=True)
|
|
|
|
|
|
|
|
if "Authorization" in headers:
|
|
|
|
_, credentials = headers["Authorization"].split()
|
|
|
|
token_data = decode_token(credentials)
|
|
|
|
if token_data is None or "email" not in token_data:
|
|
|
|
return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
|
|
|
|
|
|
|
|
user = Users.get_user_by_email(token_data["email"])
|
|
|
|
if user and user.role == "admin":
|
|
|
|
TARGET_SERVER_URL = data["url"]
|
|
|
|
return (
|
|
|
|
jsonify({"OLLAMA_API_BASE_URL": TARGET_SERVER_URL}),
|
|
|
|
200,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return (
|
|
|
|
jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}),
|
|
|
|
401,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return (
|
|
|
|
jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}),
|
|
|
|
401,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-01-04 21:30:47 +00:00
|
|
|
@app.route("/",
|
|
|
|
defaults={"path": ""},
|
|
|
|
methods=["GET", "POST", "PUT", "DELETE"])
|
2024-01-04 21:06:31 +00:00
|
|
|
@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}"
|
|
|
|
print(target_url)
|
|
|
|
|
|
|
|
# Get data from the original request
|
|
|
|
data = request.get_data()
|
|
|
|
headers = dict(request.headers)
|
|
|
|
|
|
|
|
# Basic RBAC support
|
|
|
|
if WEBUI_AUTH:
|
|
|
|
if "Authorization" in headers:
|
|
|
|
_, credentials = headers["Authorization"].split()
|
|
|
|
token_data = decode_token(credentials)
|
|
|
|
if token_data is None or "email" not in token_data:
|
|
|
|
return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
|
|
|
|
|
|
|
|
user = Users.get_user_by_email(token_data["email"])
|
|
|
|
if user:
|
|
|
|
# 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 (
|
2024-01-04 21:30:47 +00:00
|
|
|
jsonify({
|
|
|
|
"detail":
|
|
|
|
ERROR_MESSAGES.ACCESS_PROHIBITED
|
|
|
|
}),
|
2024-01-04 21:06:31 +00:00
|
|
|
401,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
pass
|
|
|
|
else:
|
2024-01-04 21:30:47 +00:00
|
|
|
return jsonify(
|
|
|
|
{"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}), 401
|
2024-01-04 21:06:31 +00:00
|
|
|
else:
|
|
|
|
return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
|
|
|
|
else:
|
|
|
|
return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
|
|
|
|
else:
|
|
|
|
pass
|
|
|
|
|
|
|
|
r = None
|
|
|
|
|
|
|
|
headers.pop("Host", None)
|
|
|
|
headers.pop("Authorization", None)
|
|
|
|
headers.pop("Origin", None)
|
|
|
|
headers.pop("Referer", None)
|
|
|
|
|
|
|
|
try:
|
|
|
|
# Make a request to the target server
|
|
|
|
r = requests.request(
|
|
|
|
method=request.method,
|
|
|
|
url=target_url,
|
|
|
|
data=data,
|
|
|
|
headers=headers,
|
|
|
|
stream=True, # Enable streaming for server-sent events
|
|
|
|
)
|
|
|
|
|
|
|
|
r.raise_for_status()
|
|
|
|
|
|
|
|
# Proxy the target server's response to the client
|
|
|
|
def generate():
|
|
|
|
for chunk in r.iter_content(chunk_size=8192):
|
|
|
|
yield chunk
|
|
|
|
|
|
|
|
response = Response(generate(), status=r.status_code)
|
|
|
|
|
|
|
|
# Copy headers from the target server's response to the client's response
|
|
|
|
for key, value in r.headers.items():
|
|
|
|
response.headers[key] = value
|
|
|
|
|
|
|
|
return response
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
error_detail = "Ollama WebUI: Server Connection Error"
|
|
|
|
if r != None:
|
|
|
|
print(r.text)
|
|
|
|
res = r.json()
|
|
|
|
if "error" in res:
|
|
|
|
error_detail = f"Ollama: {res['error']}"
|
|
|
|
print(res)
|
|
|
|
|
|
|
|
return (
|
2024-01-04 21:30:47 +00:00
|
|
|
jsonify({
|
|
|
|
"detail": error_detail,
|
|
|
|
"message": str(e),
|
|
|
|
}),
|
2024-01-04 21:06:31 +00:00
|
|
|
400,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
app.run(debug=True)
|