|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8" /> |
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|
|
|
<link |
|
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" |
|
rel="stylesheet" |
|
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" |
|
crossorigin="anonymous" |
|
/> |
|
|
|
<link |
|
href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500&display=swap" |
|
rel="stylesheet" |
|
/> |
|
|
|
<title>Grid Stability Classifier</title> |
|
<style> |
|
* { |
|
font-family: "Quicksand", sans-serif; |
|
} |
|
|
|
.product-card { |
|
padding: 10px; |
|
border: none; |
|
} |
|
|
|
.box { |
|
transition: 0.5s; |
|
border-radius: 20px; |
|
width: 300px; |
|
} |
|
|
|
.box:hover { |
|
transform: translateY(-40px); |
|
} |
|
|
|
.card-body { |
|
text-align: center; |
|
} |
|
|
|
.container { |
|
margin-top: 20px; |
|
} |
|
|
|
.form-group { |
|
margin-bottom: 15px; |
|
} |
|
|
|
.btn { |
|
background-color: rgba(40, 119, 165, 0.8); |
|
border-radius: 15px; |
|
} |
|
|
|
.btn-product { |
|
color: rgb(255, 255, 255); |
|
background-color: rgba(40, 119, 165, 0.8); |
|
border-radius: 0px 28.5px 2px; |
|
padding: 8px 50px; |
|
text-decoration: none; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<nav |
|
class="navbar navbar-expand navbar-light shadow-sm sticky-top bg-white" |
|
> |
|
<div |
|
class="collapse navbar-collapse justify-content-center" |
|
id="navbarSupportedContent" |
|
> |
|
<ul class="navbar-nav"> |
|
<li class="nav-item"> |
|
<a |
|
class="nav-link" |
|
id="navFeatures" |
|
href="#features" |
|
onclick="setActiveNav('navFeatures')" |
|
>Features</a |
|
> |
|
</li> |
|
<li class="nav-item"> |
|
<a |
|
class="nav-link" |
|
id="navClassifier" |
|
href="#classifier" |
|
onclick="setActiveNav('navClassifier')" |
|
>Classifier</a |
|
> |
|
</li> |
|
</ul> |
|
</div> |
|
</nav> |
|
|
|
<div id="features"> |
|
<h4 style="text-align: center; margin-top: 30px">Features</h4> |
|
</div> |
|
|
|
<div class="container"> |
|
<div class="product-card shadow rounded p-4"> |
|
<table class="table"> |
|
<thead> |
|
<tr> |
|
<th scope="col">Name</th> |
|
<th scope="col" style="text-align: center">Description</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
<tr> |
|
<td>tau1</td> |
|
<td> |
|
Electricity producer's reaction time in response to price change |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>tau2</td> |
|
<td> |
|
First consumers' reaction time in response to price change |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>tau3</td> |
|
<td> |
|
Second consumer's reaction time in response to price change |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>tau4</td> |
|
<td> |
|
Third consumer's reaction time in response to price change |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>p1</td> |
|
<td> |
|
Nominal power (positive real) produced by the producer (amount |
|
of electricity produced) |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>p2</td> |
|
<td> |
|
Nominal power (negative real) consumed by the first consumer |
|
(amount of electricity consumed by the first consumer) |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>p3</td> |
|
<td> |
|
Nominal power (negative real) consumed by the second consumer |
|
(amount of electricity consumed by the second consumer) |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>p4</td> |
|
<td> |
|
Nominal power (negative real) consumed by the third consumer |
|
(amount of electricity consumed by the third consumer) |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>g1</td> |
|
<td> |
|
(Gamma coefficient) proportional to price elasticity of producer |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>g2</td> |
|
<td> |
|
(Gamma coefficient) proportional to the price elasticity of the |
|
first consumer |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>g3</td> |
|
<td> |
|
(Gamma coefficient) proportional to the price elasticity of the |
|
second consumer |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>g4</td> |
|
<td> |
|
(Gamma coefficient) proportional to the price elasticity of the |
|
third consumer |
|
</td> |
|
</tr> |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
|
|
<div id="classifier"> |
|
<h4 style="text-align: center; margin-top: 60px">Classifier</h4> |
|
</div> |
|
|
|
<div class="container mb-5"> |
|
<div class="product-card shadow rounded p-4"> |
|
<form action="/" method="post"> |
|
<div class="row mb-1"> |
|
<div class="form-group"> |
|
<label for="excelFile">Upload Excel File</label> |
|
<input |
|
type="file" |
|
id="excelFile" |
|
accept=".xlsx, .xls" |
|
class="form-control" |
|
/> |
|
<a |
|
style=" |
|
float: right; |
|
text-decoration: underline; |
|
color: rgba(40, 119, 165, 0.8); |
|
cursor: pointer; |
|
" |
|
href="{{ url_for('static', filename='grid.xlsx') }}" |
|
>Unduh template excel</a |
|
> |
|
</div> |
|
</div> |
|
<p class="text-center">atau</p> |
|
<div class="row mt-3"> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>tau1</label> |
|
<input |
|
type="text" |
|
name="tau1" |
|
placeholder="tau1" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>tau2</label> |
|
<input |
|
type="text" |
|
name="tau2" |
|
placeholder="tau2" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>tau3</label> |
|
<input |
|
type="text" |
|
name="tau3" |
|
placeholder="tau3" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>tau4</label> |
|
<input |
|
type="text" |
|
name="tau4" |
|
placeholder="tau4" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="row"> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>p1</label> |
|
<input |
|
type="text" |
|
name="p1" |
|
placeholder="p1" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>p2</label> |
|
<input |
|
type="text" |
|
name="p2" |
|
placeholder="p2" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>p3</label> |
|
<input |
|
type="text" |
|
name="p3" |
|
placeholder="p3" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>p4</label> |
|
<input |
|
type="text" |
|
name="p4" |
|
placeholder="p4" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="row"> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>g1</label> |
|
<input |
|
type="text" |
|
name="g1" |
|
placeholder="g1" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>g2</label> |
|
<input |
|
type="text" |
|
name="g2" |
|
placeholder="g2" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>g3</label> |
|
<input |
|
type="text" |
|
name="g3" |
|
placeholder="g3" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="form-group"> |
|
<label>g4</label> |
|
<input |
|
type="text" |
|
name="g4" |
|
placeholder="g4" |
|
class="form-control" |
|
required |
|
/> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="d-flex justify-content-center mt-4"> |
|
<button type="submit" class="btn btn-primary w-50">Classify</button> |
|
</div> |
|
</form> |
|
</div> |
|
</div> |
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script> |
|
<script |
|
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" |
|
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" |
|
crossorigin="anonymous" |
|
></script> |
|
<script> |
|
{% if result %} |
|
Swal.fire({ |
|
title: 'Classification Result', |
|
text: '{{ result }}', |
|
icon: 'info', |
|
confirmButtonColor: '#3085d6', |
|
confirmButtonText: 'OK' |
|
}); |
|
{% endif %} |
|
</script> |
|
<script> |
|
document |
|
.getElementById("excelFile") |
|
.addEventListener("change", handleFile, false); |
|
|
|
function handleFile(event) { |
|
const file = event.target.files[0]; |
|
if (!file) return; |
|
|
|
const reader = new FileReader(); |
|
reader.onload = function (e) { |
|
const data = new Uint8Array(e.target.result); |
|
const workbook = XLSX.read(data, { type: "array" }); |
|
|
|
const sheetName = workbook.SheetNames[0]; |
|
const sheet = workbook.Sheets[sheetName]; |
|
const json = XLSX.utils.sheet_to_json(sheet, { header: 1 }); |
|
|
|
populateForm(json); |
|
}; |
|
reader.readAsArrayBuffer(file); |
|
} |
|
|
|
function populateForm(data) { |
|
const fields = data[0]; |
|
const values = data[1]; |
|
|
|
fields.forEach((field, index) => { |
|
const input = document.querySelector(`[name="${field}"]`); |
|
|
|
if (values[index] == undefined) { |
|
values[index] = 0; |
|
} |
|
|
|
if (input) { |
|
input.value = values[index]; |
|
} |
|
}); |
|
} |
|
|
|
function filterNumericInput(event) { |
|
const input = event.target; |
|
let value = input.value; |
|
|
|
value = value.replace(/[^0-9.-]/g, ""); |
|
|
|
|
|
const parts = value.split("."); |
|
if (parts.length > 2) { |
|
value = parts[0] + "." + parts.slice(1).join(""); |
|
} |
|
|
|
input.value = value; |
|
} |
|
|
|
|
|
document.querySelectorAll('input[type="text"]').forEach((input) => { |
|
input.addEventListener("input", filterNumericInput); |
|
}); |
|
</script> |
|
</body> |
|
</html> |
|
|