dodanie
This commit is contained in:
parent
8be1d0a1c9
commit
f1a48d4acb
6
.env
Normal file
6
.env
Normal file
@ -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
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
.venv/
|
||||
.idea/
|
||||
10
.idea/.gitignore
vendored
Normal file
10
.idea/.gitignore
vendored
Normal file
@ -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/
|
||||
10
.idea/Strona AI.iml
Normal file
10
.idea/Strona AI.iml
Normal file
@ -0,0 +1,10 @@
|
||||
<?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>
|
||||
13
.idea/inspectionProfiles/Project_Default.xml
Normal file
13
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<list>
|
||||
<option value="torch" />
|
||||
<option value="numpy" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
.idea/misc.xml
Normal file
7
.idea/misc.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (Strona AI)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (Strona AI)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Strona AI.iml" filepath="$PROJECT_DIR$/.idea/Strona AI.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
144
app.py
Normal file
144
app.py
Normal file
@ -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 = "<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)
|
||||
22
main.py
22
main.py
@ -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)
|
||||
1
models/Power/Readme.md
Normal file
1
models/Power/Readme.md
Normal file
@ -0,0 +1 @@
|
||||
#model Power
|
||||
BIN
models/Power/__pycache__/model.cpython-313.pyc
Normal file
BIN
models/Power/__pycache__/model.cpython-313.pyc
Normal file
Binary file not shown.
18
models/Power/description.md
Normal file
18
models/Power/description.md
Normal file
@ -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
|
||||
6
models/Power/meta.json
Normal file
6
models/Power/meta.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Power",
|
||||
"function_name": "oblicz_potega",
|
||||
"inputs": ["x","typ"],
|
||||
"description_file": "description.md"
|
||||
}
|
||||
16
models/Power/model.py
Normal file
16
models/Power/model.py
Normal file
@ -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'."
|
||||
150
static/style.css
Normal file
150
static/style.css
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
59
templates/user.html
Normal file
59
templates/user.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<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}}">
|
||||
<h3>{{name}}</h3>
|
||||
<div class="description">
|
||||
{{ model.md_content | safe }}
|
||||
</div>
|
||||
|
||||
|
||||
<form class="predict-form">
|
||||
{% for inp in model.inputs %}
|
||||
<label>{{inp}}:</label>
|
||||
<input name="{{inp}}"><br>
|
||||
{% endfor %}
|
||||
<button type="submit">Wyślij</button>
|
||||
</form>
|
||||
<div class="output" id="output-{{name}}"></div>
|
||||
{% 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>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll(".predict-form").forEach(form => {
|
||||
form.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
const parent = e.target.closest(".model-card");
|
||||
const modelName = parent.id.replace("model-", "");
|
||||
const outputDiv = parent.querySelector(".output");
|
||||
|
||||
const formData = new FormData(form);
|
||||
const response = await fetch(`/predict/${modelName}`, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
outputDiv.textContent = data.output;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user