diff --git a/.env b/.env
new file mode 100644
index 0000000..a595fb7
--- /dev/null
+++ b/.env
@@ -0,0 +1,6 @@
+SECRET_KEY=MOKO00koko
+PASSWORD_KEY=tZnq1IyFSKeBwaLa0Bx5Ge722GgrJztHHNv3jqXMswo=
+ADMIN_PASSWORD=admin
+MODEL_REPO_URL=https:/git.pathl.pl
+UPLOAD_LIMIT_MB=500
+DEBUG=True
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 0949605..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.venv/
-.idea/
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..ab1f416
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# 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/Strona AI.iml b/.idea/Strona AI.iml
new file mode 100644
index 0000000..a55366f
--- /dev/null
+++ b/.idea/Strona AI.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..539dad3
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..3769195
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..34f09f4
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e69de29..ecefae0 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,3 @@
+#Pathl.Ai cześc projektu Cafe
+
+Ceo: Maro
\ No newline at end of file
diff --git a/app.py b/app.py
new file mode 100644
index 0000000..72eb3fb
--- /dev/null
+++ b/app.py
@@ -0,0 +1,144 @@
+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 = "
Brak opisu.
"
+
+ models_with_md[name] = {**model, "md_content": md_content}
+
+ return render_template("user.html", models=models_with_md)
+# ---- PREDICT ----
+@app.route("/predict/", 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//")
+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)
diff --git a/main.py b/main.py
deleted file mode 100644
index 25c9c74..0000000
--- a/main.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from flask import Flask, request, jsonify
-
-app = Flask(__name__)
-
-# Strona główna
-@app.route("/")
-def home():
- return "AI Pathl Test działa!"
-
-# Endpoint testowy np. dla promptów AI
-@app.route("/test", methods=["POST"])
-def test_ai():
- data = request.json
- prompt = data.get("prompt", "")
- # Na razie tylko echo promptu
- response = {"response": f"Otrzymałem Twój prompt: {prompt}"}
- return jsonify(response)
-
-if __name__ == "__main__":
- print("server")
- print("dodanie")
- app.run(host="0.0.0.0", port=6000)
diff --git a/model.py b/model.py
new file mode 100644
index 0000000..e69de29
diff --git a/models/Power/Readme.md b/models/Power/Readme.md
new file mode 100644
index 0000000..6b8d77d
--- /dev/null
+++ b/models/Power/Readme.md
@@ -0,0 +1 @@
+#model Power
diff --git a/models/Power/__pycache__/model.cpython-313.pyc b/models/Power/__pycache__/model.cpython-313.pyc
new file mode 100644
index 0000000..ecf8832
Binary files /dev/null and b/models/Power/__pycache__/model.cpython-313.pyc differ
diff --git a/models/Power/description.md b/models/Power/description.md
new file mode 100644
index 0000000..c1c04e9
--- /dev/null
+++ b/models/Power/description.md
@@ -0,0 +1,18 @@
+# Model Power
+
+Ten model oblicza potęgę liczby.
+
+## Funkcje:
+
+- `oblicz_potega(x, typ)`
+
+### Parametry:
+
+- `x` (int/float): liczba do podniesienia do potęgi
+- `typ` (str): `"kwadrat"` lub `"sześcian"`
+
+### Przykłady użycia:
+
+```python
+oblicz_potega(3, "kwadrat") # wynik: 9
+oblicz_potega(2, "sześcian") # wynik: 8
diff --git a/models/Power/meta.json b/models/Power/meta.json
new file mode 100644
index 0000000..56e5e8c
--- /dev/null
+++ b/models/Power/meta.json
@@ -0,0 +1,6 @@
+{
+ "name": "Power",
+ "function_name": "oblicz_potega",
+ "inputs": ["x","typ"],
+ "description_file": "description.md"
+}
diff --git a/models/Power/model.py b/models/Power/model.py
new file mode 100644
index 0000000..80559c0
--- /dev/null
+++ b/models/Power/model.py
@@ -0,0 +1,16 @@
+def oblicz_potega(x, typ):
+ """
+ Funkcja oblicza kwadrat lub sześcian liczby x w zależności od parametru typ.
+ Parametry:
+ x (int/float): liczba, którą chcemy podnieść do potęgi
+ typ (str): "kwadrat" lub "sześcian"
+
+ Zwraca:
+ int/float: wynik działania
+ """
+ if typ == "kwadrat":
+ return x ** 2
+ elif typ == "sześcian":
+ return x ** 3
+ else:
+ return "Niepoprawny typ. Wpisz 'kwadrat' lub 'sześcian'."
diff --git a/static/style.css b/static/style.css
new file mode 100644
index 0000000..32ef883
--- /dev/null
+++ b/static/style.css
@@ -0,0 +1,150 @@
+/* Reset podstawowy */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+
+/* Body */
+body {
+ background: #f4f7fc;
+ color: #333;
+ padding: 20px;
+}
+
+/* Nagłówek */
+h2 {
+ text-align: center;
+ margin-bottom: 30px;
+ color: #4a4a4a;
+ font-size: 2em;
+}
+
+/* Kontener modeli */
+#models-container {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 20px;
+}
+
+/* Karta modelu */
+.model-card {
+ 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;
+}
+
+.model-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 12px 24px rgba(0,0,0,0.12);
+}
+
+/* Nazwa modelu */
+.model-card h3 {
+ margin-bottom: 15px;
+ color: #1a1a1a;
+ font-size: 1.4em;
+ border-bottom: 1px solid #e0e0e0;
+ padding-bottom: 5px;
+}
+
+/* Opis modelu (.md) */
+.description {
+ font-style: italic;
+ color: #555;
+ margin-bottom: 15px;
+ line-height: 1.5;
+}
+
+/* Formularz */
+form.predict-form {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+form.predict-form label {
+ font-weight: 600;
+}
+
+form.predict-form input {
+ padding: 8px 12px;
+ border-radius: 8px;
+ border: 1px solid #ccc;
+ font-size: 0.95em;
+ transition: border 0.2s, box-shadow 0.2s;
+}
+
+form.predict-form input:focus {
+ border-color: #6c63ff;
+ box-shadow: 0 0 5px rgba(108, 99, 255, 0.4);
+ outline: none;
+}
+
+/* Przycisk */
+form.predict-form button {
+ padding: 10px 15px;
+ background: #6c63ff;
+ color: #fff;
+ border: none;
+ border-radius: 10px;
+ cursor: pointer;
+ font-weight: bold;
+ transition: background 0.2s, transform 0.2s;
+}
+
+form.predict-form button:hover {
+ background: #574fd6;
+ transform: translateY(-2px);
+}
+
+/* Output */
+.output {
+ margin-top: 10px;
+ font-weight: bold;
+ color: #1a73e8;
+}
+
+/* Download linki */
+.download {
+ margin-top: 15px;
+ font-size: 0.9em;
+}
+
+.download a {
+ text-decoration: none;
+ color: #6c63ff;
+ margin-right: 10px;
+ transition: color 0.2s;
+}
+
+.download a:hover {
+ color: #574fd6;
+ text-decoration: underline;
+}
+
+/* Linie oddzielające karty */
+hr {
+ border: none;
+ height: 1px;
+ background: #e0e0e0;
+ margin: 20px 0;
+}
+
+/* Responsywność */
+@media (max-width: 600px) {
+ h2 {
+ font-size: 1.5em;
+ }
+
+ .model-card {
+ padding: 15px;
+ }
+
+ form.predict-form input, form.predict-form button {
+ font-size: 0.9em;
+ }
+}
diff --git a/templates/user.html b/templates/user.html
new file mode 100644
index 0000000..e22d990
--- /dev/null
+++ b/templates/user.html
@@ -0,0 +1,59 @@
+
+
+
+ AI Models
+
+
+
+
+Lista modeli AI
+
+ {% for name, model in models.items() %}
+
+
{{name}}
+
+ {{ model.md_content | safe }}
+
+
+
+
+
+ {% if model.meta.downloadable %}
+
+ {% endif %}
+
+
+ {% endfor %}
+
+
+
+
+