Skip to content

Instantly share code, notes, and snippets.

@amattu2
Last active December 24, 2020 12:10
Show Gist options
  • Save amattu2/c5adf92e3b83f2c59c604fdae6e0dc44 to your computer and use it in GitHub Desktop.
Save amattu2/c5adf92e3b83f2c59c604fdae6e0dc44 to your computer and use it in GitHub Desktop.
This is a simple machine learning model trainer UI kit. I used it to clean/setup multi-label classification model datasets. Based off of HTML5/CSS3, JavaScript (ES6), PHP (>= ~6.0)
-- phpMyAdmin SQL Dump
-- version 4.9.7deb1
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: Dec 24, 2020 at 07:08 AM
-- Server version: 8.0.22-0ubuntu0.20.10.2
-- PHP Version: 7.4.9
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `multi_label_appointments_model`
--
-- --------------------------------------------------------
--
-- Table structure for table `2019_Model`
--
CREATE TABLE `2019_Model` (
`ID` int NOT NULL,
`Tech` varchar(9) DEFAULT NULL,
`Service` varchar(25) DEFAULT NULL,
`Comments` varchar(279) DEFAULT NULL,
`mechanical` int NOT NULL DEFAULT '0',
`bodywork` int NOT NULL DEFAULT '0',
`diagnostic` int NOT NULL DEFAULT '0',
`suspension` int NOT NULL DEFAULT '0',
`engine` int NOT NULL DEFAULT '0',
`transmission` int NOT NULL DEFAULT '0',
`exhaust` int NOT NULL DEFAULT '0',
`electrical` int NOT NULL DEFAULT '0',
`brakes` int NOT NULL DEFAULT '0',
`tires` int NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `2019_Model`
--
ALTER TABLE `2019_Model`
ADD PRIMARY KEY (`ID`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `2019_Model`
--
ALTER TABLE `2019_Model`
MODIFY `ID` int NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
<?php
/*
Produced 2020
By https://amattu.com/links/github
Copy Alec M.
*/
/*
This file is responsible for:
- Fetching row data from a MySQL server
- Saving/updating trained model data
*/
// Files
require("db.php");
// Function navigator
if ($_GET && is_numeric($_GET['ID'])) {
echo get_result($_GET['ID']);
} else if ($_POST && isset($_POST['row'])) {
echo save_result($_POST['row']);
}
/**
Get row by ID
**/
function get_result($ID) {
if ($ID < 1) {
return false;
}
global $con;
$result = Array();
if ($stmt = $con->prepare("SELECT * FROM 2019_Model WHERE ID = ?")) {
$stmt->bind_param("i", $ID);
$stmt->bind_result($ID, $Tech, $Service, $Comments, $mechanical, $bodywork, $diagnostic, $suspension, $engine, $transmission, $exhaust, $electrical, $brakes, $tires);
if (!$stmt->execute()) {
die("Unable to execute STMT");
}
$result = Array();
while ($stmt->fetch()) {
$result = Array(
"ID" => $ID,
"Tech" => $Tech,
"Service" => $Service,
"Comments" => $Comments,
"Fields" => Array(
"mechanical" => $mechanical,
"bodywork" => $bodywork,
"diagnostic" => $diagnostic,
"suspension" => $suspension,
"engine" => $engine,
"transmission" => $transmission,
"exhaust" => $exhaust,
"electrical" => $electrical,
"brakes" => $brakes,
"tires" => $tires
)
);
}
$stmt->close();
$con->close();
return json_encode($result);
} else { die("Unable to prepare STMT"); }
}
/**
Save row by JSON object
**/
function save_result($row) {
global $con;
$row = json_decode($row, true);
if ($stmt = $con->prepare("UPDATE `2019_Model` SET `Comments` = ?, `mechanical` = ?,`bodywork` = ?, `diagnostic` = ?, `suspension` = ?, `engine` = ?, `transmission` = ?, `exhaust` = ?, `electrical` = ?, `brakes` = ?, `tires` = ? WHERE `ID` = ? LIMIT 1")) {
$stmt->bind_param("siiiiiiiiiii",
$row["Comments"],
$row["Fields"]["mechanical"],
$row["Fields"]["bodywork"],
$row["Fields"]["diagnostic"],
$row["Fields"]["suspension"],
$row["Fields"]["engine"],
$row["Fields"]["transmission"],
$row["Fields"]["exhaust"],
$row["Fields"]["electrical"],
$row["Fields"]["brakes"],
$row["Fields"]["tires"],
$row["ID"]
);
if ($stmt->execute()) {
return 1;
} else {
return 0;
}
$stmt->close();
$con->close();
} else { die("unable to prepare update"); }
}
?>
<?php
/*
Produced 2020
By https://amattu.com/links/github
Copy Alec M.
*/
// Variables
$con = mysqli_connect("localhost", "ml_appointment_trainer", "password", "multi_label_appointments_model");
// Check database connection
if (mysqli_connect_errno()) { die("unable to connect to database"); }
?>
<!DOCTYPE html>
<html lang="en" dir="ltr">
<!--
Produced 2020
By https://amattu.com/links/github
Copy Alec M.
-->
<head>
<meta charset="utf-8">
<title>Machine Learning Model Trainer</title>
<style>
body {
font-family: sans-serif;
margin: 0;
padding: 0;
color: #3b3b3b;
background: #f2f2f2;
}
.container {
width: 550px;
margin: 25px auto;
}
.train-models {
margin-top: 25px;
padding: 10px;
}
.train-model-box {
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
padding: 15px;
margin-bottom: 10px;
}
.model-field {
display: flex;
justify-content: center;
align-items: center;
min-height: 40px;
}
.field-title {
width: 105px;
font-weight: bold;
text-align: left;
user-select: none;
}
.field-input {
width: calc(100% - 105px);
}
.field-input textarea {
border: 1px solid #ccc;
border-radius: 3px;
box-sizing: border-box;
display: block;
width: 100%;
height: unset;
padding: 6px 12px;
font-size: 14px;
line-height: 1.5;
font-family: inherit;
resize: vertical;
margin-bottom: 5px;
}
.train-model-page {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
}
.button {
margin: 0 auto;
background: #3b3b3b;
padding: 10px;
color: #fff;
border-radius: 3px;
cursor: pointer;
user-select: none;
}
label {
user-select: none
}
</style>
</head>
<body>
<div class='container'>
<h2>Train Machine Learning Models</h2>
<div class='train-models'>
<div class='train-model-box'>
<div class='model-field'>
<div class='field-title'>Row ID</div>
<div class='field-input' id='row-id'>#1</div>
</div>
<div class='model-field'>
<div class='field-title'>Tech</div>
<div class='field-input' id='row-tech'>Body Shop</div>
</div>
<div class='model-field'>
<div class='field-title'>Service</div>
<div class='field-input' id='row-service'>Bodywork</div>
</div>
<div class='model-field'>
<div class='field-title'>Comments</div>
<div class='field-input'>
<textarea placeholder="Enter comments" id='row-comments' style='height: 125px'></textarea>
</div>
</div>
<div class='model-field'>
<div class='field-title'>Fields</div>
<div class='field-input'>
<div class='field-input-cb'>
<label for="field-mechanical">Mechanical</label>
<input id="field-mechanical" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-bodywork">Bodywork</label>
<input id="field-bodywork" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-diagnostic">Diagnostic</label>
<input id="field-diagnostic" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-suspension">Suspension</label>
<input id="field-suspension" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-engine">Engine</label>
<input id="field-engine" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-transmission">Transmission</label>
<input id="field-transmission" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-exhaust">Exhaust</label>
<input id="field-exhaust" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-electrical">Electrical</label>
<input id="field-electrical" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-brakes">Brakes</label>
<input id="field-brakes" type="checkbox" />
</div>
<div class='field-input-cb'>
<label for="field-tires">Tires</label>
<input id="field-tires" type="checkbox" />
</div>
</div>
</div>
</div>
<div class='train-model-page'>
<div class='button' id="train-model-prev">Previous</div>
<input type="number" min="0" max="9999" step="1" value="1" id="train-model-select" />
<div class='button' id="train-model-next">Save & Next</div>
</div>
</div>
<script>
// Variables
var current_row = {};
// Events
document.getElementById("train-model-prev").onclick = (e) => {
// Checks
if (current_row && current_row.ID && current_row.ID <= 1) {
return false;
}
build_row(current_row.ID - 1);
};
document.getElementById("train-model-select").onblur = (e) => {
// Checks
if (current_row && current_row.ID && e.target.value == current_row.ID) {
return false;
}
build_row(e.target.value);
};
document.getElementById("train-model-next").onclick = (e) => {
save_row(current_row).then((d) => {
if (!d) {
alert("Unable to save");
return false;
}
build_row((current_row && current_row.ID ? current_row.ID + 1 : 1));
});
};
document.getElementById('row-comments').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Comments = e.target.value;
};
document.getElementById('field-mechanical').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.mechanical = (e.target.checked ? 1 : 0);
};
document.getElementById('field-bodywork').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.bodywork = (e.target.checked ? 1 : 0);
};
document.getElementById('field-diagnostic').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.diagnostic = (e.target.checked ? 1 : 0);
};
document.getElementById('field-suspension').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.suspension = (e.target.checked ? 1 : 0);
};
document.getElementById('field-engine').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.engine = (e.target.checked ? 1 : 0);
};
document.getElementById('field-transmission').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.transmission = (e.target.checked ? 1 : 0);
};
document.getElementById('field-exhaust').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.exhaust = (e.target.checked ? 1 : 0);
};
document.getElementById('field-electrical').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.electrical = (e.target.checked ? 1 : 0);
};
document.getElementById('field-brakes').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.brakes = (e.target.checked ? 1 : 0);
};
document.getElementById('field-tires').onblur = (e) => {
if (!current_row || !current_row.Fields) {
return false;
}
current_row.Fields.tires = (e.target.checked ? 1 : 0);
};
// Build new row UI function
function build_row(ID) {
// Fetch new row
get_row(ID).then(d => {
// Check data
if (!d || !d.ID) {
alert("error loading row");
return false;
}
// Update reference
current_row = d;
// Update UI
document.getElementById("train-model-select").value = ID;
document.getElementById('row-id').innerText = d.ID;
document.getElementById('row-tech').innerText = d.Tech;
document.getElementById('row-service').innerText = d.Service;
document.getElementById('row-comments').value = d.Comments;
document.getElementById('field-mechanical').checked = d.Fields.mechanical;
document.getElementById('field-bodywork').checked = d.Fields.bodywork;
document.getElementById('field-diagnostic').checked = d.Fields.diagnostic;
document.getElementById('field-suspension').checked = d.Fields.suspension;
document.getElementById('field-engine').checked = d.Fields.engine;
document.getElementById('field-transmission').checked = d.Fields.transmission;
document.getElementById('field-exhaust').checked = d.Fields.exhaust;
document.getElementById('field-electrical').checked = d.Fields.electrical;
document.getElementById('field-brakes').checked = d.Fields.brakes;
document.getElementById('field-tires').checked = d.Fields.tires;
})
}
// Get row data function
async function get_row(ID) {
return new Promise(function(resolve) {
// Checks
if (!ID) { resolve(false) }
// Variables
let request = new XMLHttpRequest();
// Response
request.onreadystatechange = function() {
// Checks
if (request.readyState !== 4) { return false }
if (request.status != 200) { resolve(false) }
// Return
resolve(JSON.parse(request.responseText));
}
// Request
request.open('GET', 'api.php?ID=' + ID, true);
request.send();
});
}
// Update row data function
async function save_row(row) {
console.log(row);
return new Promise(function(resolve) {
// Variables
let form = new FormData();
let request = new XMLHttpRequest();
// Appends
form.append("row", JSON.stringify(row));
// Response
request.onreadystatechange = function() {
// Checks
if (request.readyState !== 4) { return false }
if (request.status != 200) { resolve(false) }
// Return
resolve(request.responseText);
}
// Request
request.open('POST', 'api.php', true);
request.send(form);
});
}
// Setup page
build_row(1);
</script>
</body>
</html>
@amattu2
Copy link
Author

amattu2 commented Dec 24, 2020

Preview

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment