dodanie funkcji
This commit is contained in:
parent
f1a48d4acb
commit
7530c2aa45
10
.idea/.gitignore
vendored
10
.idea/.gitignore
vendored
@ -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/
|
||||
21
.idea/Pathl.Stona.iml
Normal file
21
.idea/Pathl.Stona.iml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="Flask">
|
||||
<option name="enabled" value="true" />
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (Pathl.Stona)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Chameleon" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</module>
|
||||
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (Strona AI)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (Strona AI)" />
|
||||
<option name="sdkName" value="Python 3.13 (Pathl.Stona)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (Strona AI)" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (Pathl.Stona)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@ -2,7 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Strona AI.iml" filepath="$PROJECT_DIR$/.idea/Strona AI.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Pathl.Stona.iml" filepath="$PROJECT_DIR$/.idea/Pathl.Stona.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
107
.idea/workspace.xml
Normal file
107
.idea/workspace.xml
Normal file
@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="12dec3ca-9052-46eb-9015-fb58a43ed712" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.idea/Pathl.Stona.iml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/apks/mk.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/interpreter.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/templates/editor.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/Strona AI.iml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/app.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/static/style.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/style.css" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/templates/user.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/user.html" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Python Script" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo"><![CDATA[{
|
||||
"associatedIndex": 6
|
||||
}]]></component>
|
||||
<component name="ProjectId" id="38z9gIsEBluy4uWTRw9cg8JYPk7" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"Python.Pathl.Stona.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"ai.playground.ignore.import.keys.banner.in.settings": "true",
|
||||
"git-widget-placeholder": "main",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RunManager">
|
||||
<configuration name="Pathl.Stona" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="Pathl.Stona" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="IS_MODULE_SDK" value="false" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="RUN_TOOL" value="" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-PY-253.29346.142" />
|
||||
<option value="bundled-python-sdk-f2b7a9f6281b-6e1f45a539f7-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-253.29346.142" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="12dec3ca-9052-46eb-9015-fb58a43ed712" name="Changes" comment="" />
|
||||
<created>1769791641577</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1769791641577</updated>
|
||||
<workItem from="1769791642745" duration="1260000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||
<SUITE FILE_PATH="coverage/Pathl_Stona$Pathl_Stona.coverage" NAME="Pathl.Stona Coverage Results" MODIFIED="1769792843549" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
|
||||
</component>
|
||||
</project>
|
||||
BIN
__pycache__/app.cpython-313.pyc
Normal file
BIN
__pycache__/app.cpython-313.pyc
Normal file
Binary file not shown.
BIN
apks/__pycache__/mk.cpython-313.pyc
Normal file
BIN
apks/__pycache__/mk.cpython-313.pyc
Normal file
Binary file not shown.
5
apks/mk.py
Normal file
5
apks/mk.py
Normal file
@ -0,0 +1,5 @@
|
||||
def add(a, b):
|
||||
return a + b
|
||||
|
||||
def sub(a, b):
|
||||
return a - b
|
||||
188
app.py
188
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 = "<p>Brak opisu.</p>"
|
||||
|
||||
models_with_md[name] = {**model, "md_content": md_content}
|
||||
|
||||
return render_template("user.html", models=models_with_md)
|
||||
# ---- PREDICT ----
|
||||
|
||||
|
||||
# ---------------- EDITOR ----------------
|
||||
@app.route("/editor/<model_name>")
|
||||
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/<model_name>", 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/<filename>")
|
||||
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/<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)
|
||||
|
||||
# ---------------- MAIN ----------------
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
||||
app.run(port=4500)
|
||||
|
||||
73
interpreter.py
Normal file
73
interpreter.py
Normal file
@ -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}")
|
||||
Binary file not shown.
134
static/style.css
134
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;
|
||||
}
|
||||
|
||||
169
templates/editor.html
Normal file
169
templates/editor.html
Normal file
@ -0,0 +1,169 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>MKScript Editor – {{model_name}}</title>
|
||||
|
||||
<!-- CodeMirror CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.9/codemirror.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.9/theme/dracula.min.css">
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: #282a36;
|
||||
color: #f8f8f2;
|
||||
font-family: 'Fira Code', monospace;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: #50fa7b;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 5px 5px 5px 0;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
background: #6272a4;
|
||||
color: #f8f8f2;
|
||||
font-weight: bold;
|
||||
transition: 0.2s;
|
||||
}
|
||||
button:hover {
|
||||
background: #50fa7b;
|
||||
color: #282a36;
|
||||
}
|
||||
|
||||
#editor-container {
|
||||
margin-top: 10px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #6272a4;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
height: 400px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.panel {
|
||||
margin-top: 20px;
|
||||
background: #44475a;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.panel h3 {
|
||||
margin: 0 0 5px 0;
|
||||
font-size: 14px;
|
||||
color: #ff79c6;
|
||||
}
|
||||
|
||||
#output, #debug {
|
||||
white-space: pre-wrap;
|
||||
color: #f1fa8c;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>MKScript Editor – {{model_name}}</h2>
|
||||
|
||||
<div>
|
||||
<button onclick="run()">▶ Uruchom</button>
|
||||
<button onclick="check()">✓ Sprawdź</button>
|
||||
<button onclick="downloadFile()">💾 Pobierz</button>
|
||||
<!-- Wczytywanie pliku -->
|
||||
<input type="file" id="upload" accept=".ql" onchange="uploadFile()">
|
||||
|
||||
<a href="/" style="color:#50fa7b; margin-left: 10px;">← Wróć</a>
|
||||
</div>
|
||||
|
||||
<div id="editor-container">
|
||||
<textarea id="code">
|
||||
use mk;
|
||||
|
||||
int a = 5;
|
||||
int b = 10;
|
||||
|
||||
int c = mk.add(a, b);
|
||||
print(c);
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h3>Console Output</h3>
|
||||
<pre id="output"></pre>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h3>Debugger (zmienne)</h3>
|
||||
<pre id="debug"></pre>
|
||||
</div>
|
||||
|
||||
<!-- CodeMirror JS -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.9/codemirror.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.9/mode/python/python.min.js"></script>
|
||||
|
||||
<script>
|
||||
const editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
mode: "python",
|
||||
theme: "dracula",
|
||||
matchBrackets: true,
|
||||
indentUnit: 4,
|
||||
tabSize: 4,
|
||||
autofocus: true
|
||||
});
|
||||
|
||||
async function run() {
|
||||
const code = editor.getValue();
|
||||
const res = await fetch("/run_script", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type":"application/json"},
|
||||
body: JSON.stringify({code})
|
||||
});
|
||||
const data = await res.json();
|
||||
if(data.error){
|
||||
document.getElementById("output").textContent = "ERROR: "+data.error;
|
||||
document.getElementById("debug").textContent = "";
|
||||
}else{
|
||||
document.getElementById("output").textContent = data.output.join("\n");
|
||||
document.getElementById("debug").textContent = JSON.stringify(data.variables,null,2);
|
||||
}
|
||||
}
|
||||
|
||||
function check(){
|
||||
const code = editor.getValue();
|
||||
if(!code.includes(";")) alert("Brak średników ;");
|
||||
else alert("Składnia OK ✔");
|
||||
}
|
||||
|
||||
function downloadFile(){
|
||||
const blob = new Blob([editor.getValue()], {type:"text/plain"});
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = "{{model_name}}.ql";
|
||||
a.click();
|
||||
}
|
||||
|
||||
function uploadFile(){
|
||||
const file = document.getElementById("upload").files[0];
|
||||
if(!file) return;
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
fetch("/upload_script", {method:"POST", body:form})
|
||||
.then(r => r.text())
|
||||
.then(alert);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,42 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>AI Models</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>Lista modeli AI</h2>
|
||||
|
||||
<div id="models-container">
|
||||
{% for name, model in models.items() %}
|
||||
<div class="model-card" id="model-{{name}}">
|
||||
{% for name, model in models.items() %}
|
||||
<div class="model-card" id="model-{{name}}">
|
||||
|
||||
<!-- 3 KROPKI -->
|
||||
<div class="menu-btn" onclick="toggleMenu('{{name}}')">⋮</div>
|
||||
|
||||
<!-- WYSUWANY PANEL -->
|
||||
<div class="side-menu" id="menu-{{name}}">
|
||||
<h4>Akcje modelu</h4>
|
||||
|
||||
<input type="text" value="{{name}}" readonly>
|
||||
|
||||
<button onclick="goToEditor('{{name}}')">
|
||||
Edytor kodu
|
||||
</button>
|
||||
|
||||
<button onclick="toggleMenu('{{name}}')">
|
||||
Zamknij
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- NAZWA -->
|
||||
<h3>{{name}}</h3>
|
||||
|
||||
<!-- OPIS (Markdown -> HTML) -->
|
||||
<div class="description">
|
||||
{{ model.md_content | safe }}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- FORMULARZ -->
|
||||
<form class="predict-form">
|
||||
{% for inp in model.inputs %}
|
||||
<label>{{inp}}:</label>
|
||||
<input name="{{inp}}"><br>
|
||||
<input name="{{inp}}">
|
||||
{% endfor %}
|
||||
<button type="submit">Wyślij</button>
|
||||
</form>
|
||||
|
||||
<!-- OUTPUT -->
|
||||
<div class="output" id="output-{{name}}"></div>
|
||||
|
||||
<!-- DOWNLOAD -->
|
||||
{% if model.meta.downloadable %}
|
||||
<div class="download">
|
||||
<a href="/download/{{name}}/model.py" target="_blank">Pobierz model.py</a> |
|
||||
<a href="/download/{{name}}/description.md" target="_blank">Pobierz description.md</a> |
|
||||
<a href="/download/{{name}}/meta.json" target="_blank">Pobierz meta.json</a>
|
||||
<a href="/download/{{name}}/model.py" target="_blank">model.py</a> |
|
||||
<a href="/download/{{name}}/description.md" target="_blank">description.md</a> |
|
||||
<a href="/download/{{name}}/meta.json" target="_blank">meta.json</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ---- PREDICT ---- */
|
||||
document.querySelectorAll(".predict-form").forEach(form => {
|
||||
form.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
@ -54,6 +83,18 @@ document.querySelectorAll(".predict-form").forEach(form => {
|
||||
outputDiv.textContent = data.output;
|
||||
});
|
||||
});
|
||||
|
||||
/* ---- MENU ---- */
|
||||
function toggleMenu(name) {
|
||||
const menu = document.getElementById("menu-" + name);
|
||||
menu.classList.toggle("open");
|
||||
}
|
||||
|
||||
/* ---- EDITOR ---- */
|
||||
function goToEditor(name) {
|
||||
window.location.href = `/editor/${name}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user