<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔬 Aropha AI Biodegradation Prediction Platform</title>
<style>
/* General Styles */
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #2C4555;
color: #ffffff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background: #1E2A34;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
width: 90%;
max-width: 500px;
text-align: center;
}
/* Logo */
.logo {
width: 200px;
margin-bottom: 20px;
margin-top: 20px;
}
/* Headings */
h1 {
margin-bottom: 20px;
font-size: 24px;
color: #ffffff;
}
/* Form Groups */
.form-group {
margin-bottom: 15px;
text-align: left;
}
label {
display: block;
margin: 10px 0 5px;
font-weight: bold;
color: #ffffff;
}
/* Input Fields */
input[type="email"],
input[type="password"],
input[type="file"] {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border-radius: 5px;
background: #24343D;
color: #ffffff;
border: none;
outline: none;
}
input::placeholder {
color: #b0b8bf;
}
/* Buttons */
button,
input[type="submit"] {
width: 100%;
background-color: #007BFF;
color: #ffffff;
border: none;
padding: 12px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:hover,
input[type="submit"]:hover {
background-color: #0056b3;
}
/* Row with label + file input side by side */
.row-flex {
display: flex;
align-items: center;
gap: 0.8em;
flex-wrap: wrap;
}
/* Message Boxes */
#creditsBox,
#messages {
background: #24343D;
padding: 15px;
min-height: 50px;
border: 1px solid #007BFF;
margin-top: 15px;
white-space: pre-wrap;
border-radius: 5px;
color: #ffffff;
text-align: left; /* Align text to left */
}
/* Footer Styles */
footer {
text-align: center;
padding: 10px;
color: #b0b8bf;
font-size: 14px;
}
footer a {
color: #ffffff;
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<img src="https://www.users.aropha.com/static/assets/img/logo-rectangular.png" alt="Aropha Logo" class="logo">
<h1>Aropha's Biodegradation Prediction Platform</h1>
<form id="arophaForm">
<!-- Email -->
<div class="form-group">
<label for="email">Email:</label>
<input
type="email"
id="email"
name="email"
placeholder="Enter your email"
required
/>
</div>
<!-- Password -->
<div class="form-group">
<label for="password">Password:</label>
<input
type="password"
id="password"
name="password"
placeholder="Enter your password"
required
/>
</div>
<!-- Check Credits button -->
<div class="form-group">
<button id="checkCreditsBtn" type="button">
Check Your Credits
</button>
</div>
<!-- Spreadsheet (.xlsx) label next to file chooser -->
<div class="form-group row-flex">
<label for="spreadsheet" style="margin-bottom: 0;">
Spreadsheet (.xlsx):
</label>
<input
type="file"
id="spreadsheet"
name="spreadsheet"
accept=".xlsx"
required
/>
</div>
<!-- Submit Template Spreadsheet button -->
<div class="form-group">
<button id="submitBtn" type="submit">
Submit Template Spreadsheet
</button>
</div>
</form>
<!-- Displays credit info from the server -->
<div id="creditsBox"></div>
<!-- Displays messages for final spreadsheet submission -->
<div id="messages"></div>
</div>
<footer>
<p>
Follow us on <a href="https://www.linkedin.com/company/aropha/">LinkedIn</a> | © 2025 Aropha Inc. All Rights Reserved.
</p>
</footer>
<script>
// Utility: convert ArrayBuffer to Base64
function arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
// 1) Check Your Credits
document.getElementById('checkCreditsBtn').addEventListener('click', async () => {
const creditsBox = document.getElementById('creditsBox');
creditsBox.textContent = 'Checking credits...';
const email = document.getElementById('email').value.trim();
const password = document.getElementById('password').value;
if (!email || !password) {
creditsBox.textContent = 'Please enter Email and Password first.';
return;
}
// Construct JSON payload
const json_data = {
email,
password,
filename: 'filename_blank',
raw_data: 'blank'
};
try {
const response = await fetch('https://modelserver.aropha.com/run_twin_engines', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(json_data)
});
if (!response.ok) {
try {
const errorData = await response.json();
console.log('Full error response:', errorData);
if (errorData.detail) {
creditsBox.textContent = errorData.detail;
} else {
creditsBox.textContent = `Error: ${JSON.stringify(errorData, null, 2)}`;
}
} catch (jsonError) {
const rawError = await response.text();
console.error('Raw error response:', rawError);
creditsBox.textContent = `Error: Could not parse JSON. Raw response: ${rawError}`;
}
return;
}
const responseData = await response.json();
if (typeof responseData.credits !== 'undefined') {
creditsBox.textContent = `You have ${responseData.credits} credits remaining.`;
} else {
creditsBox.textContent = 'Credits info not found in server response.';
}
} catch (err) {
creditsBox.textContent = 'Error: ' + err;
}
});
// 2) Submit the form (spreadsheet upload)
document.getElementById('arophaForm').addEventListener('submit', async function (event) {
event.preventDefault(); // Prevent normal form POST
const messagesDiv = document.getElementById('messages');
messagesDiv.textContent = 'Preparing and uploading...';
const email = document.getElementById('email').value.trim();
const password = document.getElementById('password').value;
const fileInput = document.getElementById('spreadsheet');
if (!fileInput.files || fileInput.files.length === 0) {
messagesDiv.textContent = 'Please select a spreadsheet file.';
return;
}
const file = fileInput.files[0];
const filename = file.name;
// Read the file as an ArrayBuffer
let fileBuffer;
try {
fileBuffer = await file.arrayBuffer();
} catch (err) {
messagesDiv.textContent = 'Error reading file: ' + err;
return;
}
// Convert the ArrayBuffer to Base64
const raw_data_b64 = arrayBufferToBase64(fileBuffer);
// Construct JSON payload
const json_data = {
email,
password,
filename,
raw_data: raw_data_b64
};
// POST to Aropha modelserver
try {
const response = await fetch('https://modelserver.aropha.com/run_twin_engines', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(json_data)
});
if (response.status === 422) {
const responseData = await response.json();
if (responseData.detail) {
messagesDiv.textContent = responseData.detail;
} else {
messagesDiv.textContent = JSON.stringify(responseData, null, 2);
}
if (responseData['flag data']) {
const flagBase64 = responseData['flag data'];
const byteChars = atob(flagBase64);
const byteNumbers = new Array(byteChars.length);
for (let i = 0; i < byteChars.length; i++) {
byteNumbers[i] = byteChars.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'application/gzip' });
const now = new Date();
const currentDate = now.toISOString().split('T')[0];
const currentTime = now.toTimeString().split(' ')[0].replace(/:/g, '-');
const templateFileName = filename.replace(/\.[^/.]+$/, '');
const dynamicFileName = `flag_notes_${templateFileName}_${currentDate}_${currentTime}.gz`;
const downloadUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = dynamicFileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(downloadUrl);
}
return;
} else if (!response.ok) {
try {
const errorData = await response.json();
console.log('Full error response:', errorData);
if (errorData.detail) {
messagesDiv.textContent = errorData.detail;
} else {
messagesDiv.textContent = `Error: ${JSON.stringify(errorData, null, 2)}`;
}
} catch (jsonError) {
const rawError = await response.text();
console.error('Raw error response:', rawError);
messagesDiv.textContent = `Error: Could not parse JSON. Raw response: ${rawError}`;
}
return;
}
if (response.status === 200) {
const message = await response.json();
messagesDiv.textContent = message.detail;
}
} catch (err) {
messagesDiv.textContent = 'Error submitting data: ' + err;
}
});
</script>
</body>
</html>
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter