145 lines
4.4 KiB
Python
145 lines
4.4 KiB
Python
|
|
from flask import Flask, request, render_template, jsonify, send_from_directory
|
||
|
|
import os, json, importlib.util
|
||
|
|
from werkzeug.utils import secure_filename
|
||
|
|
import markdown
|
||
|
|
app = Flask(__name__)
|
||
|
|
UPLOAD_FOLDER = "models"
|
||
|
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||
|
|
ADMIN_KEY = "supersecretadminkey"
|
||
|
|
|
||
|
|
MODELS = {}
|
||
|
|
|
||
|
|
def load_models():
|
||
|
|
for folder in os.listdir(UPLOAD_FOLDER):
|
||
|
|
path = os.path.join(UPLOAD_FOLDER, folder)
|
||
|
|
if not os.path.isdir(path):
|
||
|
|
continue
|
||
|
|
meta_path = os.path.join(path, "meta.json")
|
||
|
|
if not os.path.exists(meta_path):
|
||
|
|
continue
|
||
|
|
with open(meta_path) as f:
|
||
|
|
meta = json.load(f)
|
||
|
|
func_name = meta.get("function_name")
|
||
|
|
if not func_name:
|
||
|
|
continue
|
||
|
|
|
||
|
|
py_file = os.path.join(path, "model.py")
|
||
|
|
spec = importlib.util.spec_from_file_location("model_module", py_file)
|
||
|
|
module = importlib.util.module_from_spec(spec)
|
||
|
|
spec.loader.exec_module(module)
|
||
|
|
|
||
|
|
func = getattr(module, func_name)
|
||
|
|
MODELS[folder] = {
|
||
|
|
"func": func,
|
||
|
|
"inputs": meta.get("inputs", []),
|
||
|
|
"meta": meta,
|
||
|
|
"path": path
|
||
|
|
}
|
||
|
|
|
||
|
|
load_models()
|
||
|
|
|
||
|
|
# ---- DASHBOARD ----
|
||
|
|
@app.route("/")
|
||
|
|
def dashboard():
|
||
|
|
models_with_md = {}
|
||
|
|
for name, model in MODELS.items():
|
||
|
|
md_content = ""
|
||
|
|
try:
|
||
|
|
md_path = os.path.join(model["path"], model["meta"]["description_file"])
|
||
|
|
with open(md_path, "r", encoding="utf-8") as f:
|
||
|
|
md_text = f.read()
|
||
|
|
# konwersja Markdown -> HTML
|
||
|
|
md_content = markdown.markdown(md_text)
|
||
|
|
except Exception:
|
||
|
|
md_content = "<p>Brak opisu.</p>"
|
||
|
|
|
||
|
|
models_with_md[name] = {**model, "md_content": md_content}
|
||
|
|
|
||
|
|
return render_template("user.html", models=models_with_md)
|
||
|
|
# ---- PREDICT ----
|
||
|
|
@app.route("/predict/<model_name>", methods=["POST"])
|
||
|
|
def predict(model_name):
|
||
|
|
model_entry = MODELS.get(model_name)
|
||
|
|
if not model_entry:
|
||
|
|
return jsonify({"output": "Model nie istnieje"}), 404
|
||
|
|
|
||
|
|
func = model_entry["func"]
|
||
|
|
inputs = model_entry["inputs"]
|
||
|
|
kwargs = {}
|
||
|
|
for inp in inputs:
|
||
|
|
kwargs[inp] = request.form.get(inp)
|
||
|
|
|
||
|
|
try:
|
||
|
|
for k in kwargs:
|
||
|
|
try:
|
||
|
|
kwargs[k] = float(kwargs[k])
|
||
|
|
except:
|
||
|
|
pass
|
||
|
|
output = func(**kwargs)
|
||
|
|
except Exception as e:
|
||
|
|
output = str(e)
|
||
|
|
|
||
|
|
return jsonify({"output": str(output)})
|
||
|
|
|
||
|
|
# ---- ADD MODEL ----
|
||
|
|
@app.route("/add_model", methods=["POST"])
|
||
|
|
def add_model():
|
||
|
|
admin_key = request.form.get("admin_key")
|
||
|
|
if admin_key != ADMIN_KEY:
|
||
|
|
return "Brak dostępu", 403
|
||
|
|
|
||
|
|
name = request.form["name"]
|
||
|
|
function_name = request.form["function_name"]
|
||
|
|
inputs = request.form.getlist("inputs")
|
||
|
|
model_py = request.files["model_py"]
|
||
|
|
description_file = request.files["description"]
|
||
|
|
|
||
|
|
folder_name = secure_filename(name)
|
||
|
|
folder_path = os.path.join(UPLOAD_FOLDER, folder_name)
|
||
|
|
os.makedirs(folder_path, exist_ok=True)
|
||
|
|
|
||
|
|
# zapis plików
|
||
|
|
model_py.save(os.path.join(folder_path, "model.py"))
|
||
|
|
description_file.save(os.path.join(folder_path, "description.md"))
|
||
|
|
|
||
|
|
# meta.json
|
||
|
|
meta = {
|
||
|
|
"name": name,
|
||
|
|
"function_name": function_name,
|
||
|
|
"inputs": inputs,
|
||
|
|
"description_file": "description.md",
|
||
|
|
"downloadable": True, # można pobrać pliki
|
||
|
|
"type": request.form.get("type", "algorithmic")
|
||
|
|
}
|
||
|
|
with open(os.path.join(folder_path, "meta.json"), "w") as f:
|
||
|
|
json.dump(meta, f)
|
||
|
|
|
||
|
|
# załaduj od razu
|
||
|
|
spec = importlib.util.spec_from_file_location("model_module", os.path.join(folder_path, "model.py"))
|
||
|
|
module = importlib.util.module_from_spec(spec)
|
||
|
|
spec.loader.exec_module(module)
|
||
|
|
func = getattr(module, function_name)
|
||
|
|
|
||
|
|
MODELS[folder_name] = {
|
||
|
|
"func": func,
|
||
|
|
"inputs": inputs,
|
||
|
|
"meta": meta,
|
||
|
|
"path": folder_path
|
||
|
|
}
|
||
|
|
|
||
|
|
return "Dodano model!"
|
||
|
|
|
||
|
|
# ---- DOWNLOAD FILE ----
|
||
|
|
@app.route("/download/<model_name>/<file_name>")
|
||
|
|
def download_file(model_name, file_name):
|
||
|
|
model_entry = MODELS.get(model_name)
|
||
|
|
if not model_entry:
|
||
|
|
return "Model nie istnieje", 404
|
||
|
|
folder_path = model_entry["path"]
|
||
|
|
if file_name not in ["model.py", "description.md", "meta.json"]:
|
||
|
|
return "Nieprawidłowy plik", 400
|
||
|
|
return send_from_directory(folder_path, file_name, as_attachment=True)
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
app.run(debug=True)
|