diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index ab1f416..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Ignored default folder with query files -/queries/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/Pathl.Stona.iml b/.idea/Pathl.Stona.iml new file mode 100644 index 0000000..024b922 --- /dev/null +++ b/.idea/Pathl.Stona.iml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/Strona AI.iml b/.idea/Strona AI.iml deleted file mode 100644 index a55366f..0000000 --- a/.idea/Strona AI.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 3769195..6b805dc 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 34f09f4..1653e50 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..aadd831 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1769791641577 + + + + + + + + + \ No newline at end of file diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc new file mode 100644 index 0000000..1af1a6c Binary files /dev/null and b/__pycache__/app.cpython-313.pyc differ diff --git a/apks/__pycache__/mk.cpython-313.pyc b/apks/__pycache__/mk.cpython-313.pyc new file mode 100644 index 0000000..c341966 Binary files /dev/null and b/apks/__pycache__/mk.cpython-313.pyc differ diff --git a/apks/mk.py b/apks/mk.py new file mode 100644 index 0000000..6cddd28 --- /dev/null +++ b/apks/mk.py @@ -0,0 +1,5 @@ +def add(a, b): + return a + b + +def sub(a, b): + return a - b diff --git a/app.py b/app.py index 72eb3fb..9a658a4 100644 --- a/app.py +++ b/app.py @@ -1,17 +1,27 @@ -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" +from flask import Flask, request, render_template, jsonify, send_file +import os, json, importlib, importlib.util, sys, re +from markdown import markdown +app = Flask(__name__) + +# FOLDERS +UPLOAD_FOLDER = "scripts" +MODELS_FOLDER = "models" +APKS_FOLDER = "apks" +os.makedirs(UPLOAD_FOLDER, exist_ok=True) +os.makedirs(MODELS_FOLDER, exist_ok=True) +sys.path.insert(0, os.path.join(os.getcwd(), APKS_FOLDER)) + +# GLOBAL MODELS MODELS = {} +# ---- Load models at startup ---- def load_models(): - for folder in os.listdir(UPLOAD_FOLDER): - path = os.path.join(UPLOAD_FOLDER, folder) + global MODELS + MODELS = {} + + for folder in os.listdir(MODELS_FOLDER): + path = os.path.join(MODELS_FOLDER, folder) if not os.path.isdir(path): continue meta_path = os.path.join(path, "meta.json") @@ -38,7 +48,8 @@ def load_models(): load_models() -# ---- DASHBOARD ---- + +# ---------------- DASHBOARD ---------------- @app.route("/") def dashboard(): models_with_md = {} @@ -47,16 +58,81 @@ def dashboard(): 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 = markdown(f.read()) + except: md_content = "

Brak opisu.

" - models_with_md[name] = {**model, "md_content": md_content} return render_template("user.html", models=models_with_md) -# ---- PREDICT ---- + + +# ---------------- EDITOR ---------------- +@app.route("/editor/") +def editor(model_name): + return render_template("editor.html", model_name=model_name) + + +# ---------------- RUN SCRIPT (MKScript) ---------------- +@app.route("/run_script", methods=["POST"]) +def run_script(): + code = request.json.get("code", "") + output = [] + variables = {} + modules = {} + + try: + lines = code.split(";") + for line in lines: + line = line.strip() + if not line: + continue + + # use mk + if line.startswith("use "): + name = line.split()[1] + mod = importlib.import_module(name) + modules[name] = mod + variables[name] = mod + continue + + # print(...) + if line.startswith("print"): + inside = line[line.find("(")+1:line.rfind(")")] + output.append(str(eval_expr(inside, variables))) + continue + + # typy int/float/bool + if any(line.startswith(t) for t in ["int ", "float ", "bool "]): + _, rest = line.split(" ", 1) + var, expr = rest.split("=") + variables[var.strip()] = eval_expr(expr.strip(), variables) + continue + + # wywołanie funkcji np mk.add(1,2) + if "." in line and "(" in line: + obj, rest = line.split(".", 1) + fname = rest[:rest.find("(")] + args = rest[rest.find("(")+1:rest.find(")")] + args = [eval_expr(a.strip(), variables) for a in args.split(",")] + result = getattr(modules[obj], fname)(*args) + variables["_"] = result + continue + + except Exception as e: + return jsonify({"error": str(e)}) + + return jsonify({ + "output": output, + "variables": {k: str(v) for k, v in variables.items()} + }) + + +def eval_expr(expr, variables): + expr = expr.replace("true", "True").replace("false", "False") + return eval(expr, {}, variables) + + +# ---------------- PREDICT ---------------- @app.route("/predict/", methods=["POST"]) def predict(model_name): model_entry = MODELS.get(model_name) @@ -65,9 +141,7 @@ def predict(model_name): func = model_entry["func"] inputs = model_entry["inputs"] - kwargs = {} - for inp in inputs: - kwargs[inp] = request.form.get(inp) + kwargs = {inp: request.form.get(inp) for inp in inputs} try: for k in kwargs: @@ -81,64 +155,28 @@ def predict(model_name): 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"] +# ---------------- DOWNLOAD SCRIPT ---------------- +@app.route("/download_script/") +def download_script(filename): + path = os.path.join(UPLOAD_FOLDER, filename) + if os.path.exists(path): + return send_file(path, as_attachment=True) + return "Plik nie istnieje", 404 - 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")) +# ---------------- UPLOAD SCRIPT ---------------- +@app.route("/upload_script", methods=["POST"]) +def upload_script(): + file = request.files.get("file") + if not file: + return "Nie przesłano pliku", 400 + filename = file.filename + path = os.path.join(UPLOAD_FOLDER, filename) + file.save(path) + return "OK" - # 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//") -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) +# ---------------- MAIN ---------------- if __name__ == "__main__": - app.run(debug=True) + app.run(port=4500) diff --git a/interpreter.py b/interpreter.py new file mode 100644 index 0000000..57c2a0d --- /dev/null +++ b/interpreter.py @@ -0,0 +1,73 @@ +import re, importlib + +variables = {} +modules = {} +functions = {} + +# Rejestracja “handlerów” dla linii +handlers = [] + +def eval_expr(expr): + """Bezpieczne obliczanie wyrażeń z użyciem zmiennych""" + expr = expr.replace("true", "True").replace("false", "False") + return eval(expr, {}, variables) + +def handle_use(line): + if line.startswith("use "): + name = line.split()[1] + modules[name] = importlib.import_module(f"apks.{name}") + variables[name] = modules[name] + return True + return False + +def handle_print(line): + if line.startswith("print"): + inside = re.search(r"\((.*)\)", line).group(1) + print(eval_expr(inside)) + return True + return False + +def handle_var(line): + for t in ["int ", "float ", "bool ", "string "]: + if line.startswith(t): + _, rest = line.split(" ", 1) + var, expr = rest.split("=") + val = expr.strip() + if t.strip() == "string": + val = val.strip('"').strip("'") + else: + val = eval_expr(val) + variables[var.strip()] = val + return True + return False + +def handle_func_call(line): + if "." in line and "(" in line: + obj, rest = line.split(".", 1) + fname = rest[:rest.find("(")] + args_str = rest[rest.find("(")+1:rest.rfind(")")] + args = [eval_expr(a.strip()) for a in args_str.split(",") if a.strip()] + result = getattr(modules[obj], fname)(*args) + variables["_"] = result # ostatni wynik + return True + return False + +# Dodajemy wszystkie handlery do listy +handlers.extend([handle_use, handle_print, handle_var, handle_func_call]) + +def run(code): + """Interpreter MKScript""" + lines = code.split(";") + for line in lines: + line = line.strip() + if not line or line.startswith("//"): # komentarze + continue + + # uruchamiamy wszystkie handlery aż któryś obsłuży linię + handled = False + for h in handlers: + if h(line): + handled = True + break + if not handled: + print(f"Nieznana linia: {line}") diff --git a/models/Power/__pycache__/model.cpython-313.pyc b/models/Power/__pycache__/model.cpython-313.pyc index ecf8832..00addeb 100644 Binary files a/models/Power/__pycache__/model.cpython-313.pyc and b/models/Power/__pycache__/model.cpython-313.pyc differ diff --git a/static/style.css b/static/style.css index 32ef883..087bb67 100644 --- a/static/style.css +++ b/static/style.css @@ -1,4 +1,6 @@ -/* Reset podstawowy */ +/* ========================= + RESET PODSTAWOWY +========================= */ * { margin: 0; padding: 0; @@ -6,14 +8,18 @@ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } -/* Body */ +/* ========================= + BODY +========================= */ body { background: #f4f7fc; color: #333; padding: 20px; } -/* Nagłówek */ +/* ========================= + NAGŁÓWEK +========================= */ h2 { text-align: center; margin-bottom: 30px; @@ -21,20 +27,26 @@ h2 { font-size: 2em; } -/* Kontener modeli */ +/* ========================= + KONTENER MODELI +========================= */ #models-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 20px; } -/* Karta modelu */ +/* ========================= + KARTA MODELU +========================= */ .model-card { + position: relative; background: #ffffff; border-radius: 15px; padding: 20px; box-shadow: 0 6px 18px rgba(0,0,0,0.08); transition: transform 0.2s, box-shadow 0.2s; + overflow: hidden; } .model-card:hover { @@ -42,7 +54,76 @@ h2 { box-shadow: 0 12px 24px rgba(0,0,0,0.12); } -/* Nazwa modelu */ +/* ========================= + 3 KROPKI (MENU) +========================= */ +.menu-btn { + position: absolute; + top: 12px; + right: 14px; + cursor: pointer; + font-size: 22px; + color: #777; + user-select: none; +} + +.menu-btn:hover { + color: #000; +} + +/* ========================= + BOCZNY PANEL (SLIDE) +========================= */ +.side-menu { + position: absolute; + top: 0; + right: -260px; + width: 250px; + height: 100%; + background: #111; + color: #fff; + padding: 20px; + transition: right 0.3s ease; + z-index: 20; + display: flex; + flex-direction: column; + gap: 10px; +} + +.side-menu.open { + right: 0; +} + +.side-menu h4 { + margin-bottom: 10px; + border-bottom: 1px solid #333; + padding-bottom: 5px; +} + +.side-menu input { + padding: 8px; + border-radius: 6px; + border: none; + font-size: 0.9em; +} + +.side-menu button { + padding: 8px; + border-radius: 8px; + border: none; + cursor: pointer; + font-weight: bold; + background: #6c63ff; + color: white; +} + +.side-menu button:hover { + background: #574fd6; +} + +/* ========================= + NAZWA MODELU +========================= */ .model-card h3 { margin-bottom: 15px; color: #1a1a1a; @@ -51,7 +132,9 @@ h2 { padding-bottom: 5px; } -/* Opis modelu (.md) */ +/* ========================= + OPIS MODELU (Markdown) +========================= */ .description { font-style: italic; color: #555; @@ -59,7 +142,9 @@ h2 { line-height: 1.5; } -/* Formularz */ +/* ========================= + FORMULARZ +========================= */ form.predict-form { display: flex; flex-direction: column; @@ -84,7 +169,9 @@ form.predict-form input:focus { outline: none; } -/* Przycisk */ +/* ========================= + PRZYCISK +========================= */ form.predict-form button { padding: 10px 15px; background: #6c63ff; @@ -101,14 +188,18 @@ form.predict-form button:hover { transform: translateY(-2px); } -/* Output */ +/* ========================= + OUTPUT +========================= */ .output { margin-top: 10px; font-weight: bold; color: #1a73e8; } -/* Download linki */ +/* ========================= + DOWNLOAD +========================= */ .download { margin-top: 15px; font-size: 0.9em; @@ -126,7 +217,9 @@ form.predict-form button:hover { text-decoration: underline; } -/* Linie oddzielające karty */ +/* ========================= + LINIE +========================= */ hr { border: none; height: 1px; @@ -134,7 +227,9 @@ hr { margin: 20px 0; } -/* Responsywność */ +/* ========================= + RESPONSYWNOŚĆ +========================= */ @media (max-width: 600px) { h2 { font-size: 1.5em; @@ -144,7 +239,18 @@ hr { padding: 15px; } - form.predict-form input, form.predict-form button { + form.predict-form input, + form.predict-form button { font-size: 0.9em; } } +.side-menu { + pointer-events: none; +} + +.side-menu.open { + pointer-events: auto; +} +.side-menu { + position: fixed; +} diff --git a/templates/editor.html b/templates/editor.html new file mode 100644 index 0000000..0df8cb8 --- /dev/null +++ b/templates/editor.html @@ -0,0 +1,169 @@ + + + + +MKScript Editor – {{model_name}} + + + + + + + + + +

MKScript Editor – {{model_name}}

+ +
+ + + + + + + ← Wróć +
+ +
+ +
+ +
+

Console Output

+

+
+ +
+

Debugger (zmienne)

+

+
+ + + + + + + + + diff --git a/templates/user.html b/templates/user.html index e22d990..73f1fed 100644 --- a/templates/user.html +++ b/templates/user.html @@ -1,42 +1,71 @@ - + + AI Models - - + +

Lista modeli AI

+
- {% for name, model in models.items() %} -
-

{{name}}

-
- {{ model.md_content | safe }} -
+{% for name, model in models.items() %} +
+ + -
+ + + + +

{{name}}

+ + +
+ {{ model.md_content | safe }} +
+ + + {% for inp in model.inputs %} - -
+ + {% endfor %} -
-
- {% if model.meta.downloadable %} - - {% endif %} + + + +
+ + + {% if model.meta.downloadable %} + -
- {% endfor %} + {% endif %} + +
+{% endfor %}
+