42Cummer's picture
Upload 9 files
45dcc02 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AURELIUS | BATTERY OPTIMIZER</title>
<link rel="icon" type="image/png" href="/static/favicon.png">
<style>
/* "Cyberpunk Lab" Aesthetic */
body { font-family: 'Courier New', monospace; background-color: #0d1117; color: #c9d1d9; max-width: 950px; margin: 40px auto; padding: 20px; font-size: 16px; }
h1 { border-bottom: 1px solid #30363d; padding-bottom: 10px; color: #58a6ff; letter-spacing: 2px;}
.control-panel { background: #161b22; padding: 25px; border: 1px solid #30363d; border-radius: 6px; margin-bottom: 25px; box-shadow: 0 4px 12px rgba(0,0,0,0.5); }
label { display: block; margin-top: 15px; margin-bottom: 5px; color: #8b949e; font-size: 15px; text-transform: uppercase; letter-spacing: 1px; }
input, textarea, button { width: 100%; box-sizing: border-box; background: #0d1117; border: 1px solid #30363d; color: #c9d1d9; font-family: inherit; font-size: 16px; }
input { padding: 10px; }
textarea { padding: 10px; resize: vertical; font-size: 16px; }
textarea:focus { outline: none; border-color: #58a6ff; }
/* Action Buttons */
.btn-group { display: flex; gap: 10px; margin-bottom: 10px; }
.btn-small { width: auto; padding: 5px 15px; font-size: 14px; background: #21262d; cursor: pointer; border-radius: 4px; transition: all 0.2s; }
.btn-small:hover { background: #30363d; border-color: #8b949e; }
.btn-primary { margin-top: 20px; padding: 15px; background: #238636; color: white; cursor: pointer; font-weight: bold; border: none; font-size: 14px; text-transform: uppercase; letter-spacing: 1px; }
.btn-primary:hover { background: #2ea043; }
/* Results Table */
table { width: 100%; border-collapse: collapse; margin-top: 30px; font-size: 16px; }
th, td { text-align: left; padding: 12px; border-bottom: 1px solid #21262d; }
th { color: #8b949e; text-transform: uppercase; font-size: 14px; }
/* Status Indicators */
.status-stable { color: #3fb950; font-weight: bold; }
.status-critical { color: #f85149; font-weight: bold; }
.status-warn { color: #d29922; }
/* Animation */
.log-entry { opacity: 0; animation: fadeIn 0.4s forwards; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
</style>
</head>
<body>
<h1>AURELIUS // BATTERY OPTIMIZER</h1>
<div class="control-panel">
<div style="display: flex; gap: 20px;">
<div style="flex: 1;">
<label>Host Formula</label>
<input type="text" id="host" value="Li3PS4">
</div>
<div style="flex: 1;">
<label>Substitution Site</label>
<input type="text" id="site" value="S">
</div>
</div>
<label>Doping Strategies (JSON Batch)</label>
<div class="btn-group">
<button class="btn-small" onclick="loadExample('simple')">LOAD: Single Dopants</button>
<button class="btn-small" onclick="loadExample('complex')">LOAD: High-Entropy Mix</button>
<button class="btn-small" onclick="loadExample('stress')">LOAD: Stress Test (Solubility)</button>
</div>
<textarea id="jsonInput" rows="8"></textarea>
<button class="btn-primary" onclick="startSimulation()">>> INITIATE SIMULATION STREAM</button>
</div>
<div id="statusLine" style="color: #8b949e; margin-bottom: 10px; font-size: 15px; min-height: 20px;">SYSTEM READY. AWAITING INPUT.</div>
<table id="resultsTable">
<thead>
<tr>
<th style="width: 30%">Composition Strategy</th>
<th>Pred. Voltage</th>
<th>Lattice Strain</th>
<th>Stability Verdict</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
// --- 1. PRE-LOAD DATA FUNCTION ---
function loadExample(type) {
const data = {
simple: `[
{"Cl": 0.1},
{"Br": 0.1},
{"I": 0.05}
]`,
complex: `[
{"Cl": 0.1, "Br": 0.1},
{"I": 0.05, "F": 0.05},
{"Cl": 0.2, "I": 0.02},
{"Br": 0.15, "Cl": 0.05}
]`,
stress: `[
{"Cl": 0.9},
{"I": 0.5},
{"F": 0.5, "Cl": 0.5}
]`
};
document.getElementById("jsonInput").value = data[type];
document.getElementById("jsonInput").style.borderColor = "#30363d"; // Reset color
}
// Initialize with simple data
loadExample('simple');
// --- 2. MAIN SIMULATION LOGIC ---
async function startSimulation() {
const tableBody = document.querySelector("#resultsTable tbody");
const statusLine = document.getElementById("statusLine");
const inputArea = document.getElementById("jsonInput");
// UX: Reset
tableBody.innerHTML = "";
statusLine.innerText = "PARSING BATCH INSTRUCTIONS...";
inputArea.style.borderColor = "#30363d";
// A. VALIDATE JSON
let parsedRecipes;
try {
parsedRecipes = JSON.parse(inputArea.value);
} catch (e) {
statusLine.innerHTML = `<span style="color: #f85149">⚠️ SYNTAX ERROR: ${e.message}</span>`;
inputArea.style.borderColor = "#f85149";
return;
}
if (!Array.isArray(parsedRecipes)) {
statusLine.innerHTML = `<span style="color: #f85149">⚠️ FORMAT ERROR: Root must be a list [...]</span>`;
return;
}
// B. CONNECT TO STREAM
statusLine.innerText = "ESTABLISHING UPLINK TO PHYSICS ENGINE...";
try {
const payload = {
host_formula: document.getElementById("host").value,
host_site_element: document.getElementById("site").value,
recipes: parsedRecipes
};
const response = await fetch("/simulate_stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error(await response.text());
// C. READ THE STREAM
const reader = response.body.getReader();
const decoder = new TextDecoder();
statusLine.innerText = "RECEIVING TELEMETRY STREAM...";
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split("\n");
for (const line of lines) {
if (!line.trim()) continue;
try {
const data = JSON.parse(line);
if (data.type === "meta") {
const source = data.base_properties.source.includes("Real") ? "REAL" : "ESTIMATED";
statusLine.innerText = `CONNECTED: ${data.host_system} | DATA SOURCE: ${source}`;
}
else if (data.type === "data") {
addRow(data);
}
} catch (e) { console.error(e); }
}
}
statusLine.innerText = "BATCH PROCESSING COMPLETE.";
} catch (err) {
statusLine.innerHTML = `<span style="color: #f85149">❌ SYSTEM FAILURE: ${err.message}</span>`;
}
}
function addRow(data) {
const tableBody = document.querySelector("#resultsTable tbody");
const row = document.createElement("tr");
row.className = "log-entry";
let statusClass = "status-warn";
if (data.stability_status.includes("Stable")) statusClass = "status-stable";
if (data.stability_status.includes("Critical") || data.stability_status.includes("Collapse")) statusClass = "status-critical";
row.innerHTML = `
<td><strong style="color: #c9d1d9">${data.recipe_description}</strong></td>
<td>${data.predicted_voltage.toFixed(3)} V</td>
<td>${data.lattice_strain.toFixed(1)} MJ</td>
<td class="${statusClass}">${data.stability_status}</td>
`;
tableBody.appendChild(row);
}
</script>
</body>
</html>