summarizer-website/templates/index.html

204 lines
7.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script>
<title>AI Text Summarizer</title>
</head>
<body>
<style>
.lds-dual-ring {
display: inline-block;
width: 10px;
height: 23px;
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 23px;
height: 23px;
margin: 8px;
border-radius: 50%;
border: 6px solid var(--bs-blue);
border-color: var(--bs-blue) transparent var(--bs-blue) transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
<div class="container">
<h1 class="my-4">AI Text Summarizer</h1>
<form id="summarize-form" class="form-inline">
<div class="form-group">
<div class="mb-3">
<label for="text" class="form-label">Enter text to summarize:</label>
<textarea id="text" name="text" class="form-control" rows="10" required></textarea>
</div>
<div class="mb-3">
<div class="dropdown d-inline-block">
<label for="model">Select model:</label>
<select id="model" name="model" class="form-select"
style="width:unset!important;display:inline-block!important"
onchange='updateTokenCount(document.getElementById("text"))'>
<option value="gpt-3.5-turbo" selected>GPT-3</option>
<option value="gpt-4">GPT-4</option>
<option value="text-davinci-003">text-davinci-003</option>
</select>
</div>
</div>
<!-- <div class="mb-3">-->
<!-- <div data-toggle="tooltip" data-placement="top"-->
<!-- title='Tell the AI not to communicate with the user. If you are getting summaries that begin with things like "The user", enable this.'>-->
<!-- <input type="checkbox" id="depersonify" name="depersonify" value="depersonify">-->
<!-- <label for="depersonify"> De-personfiy</label>-->
<!-- </div>-->
<!-- </div>-->
<div class="mb-3">
<div data-toggle="tooltip" data-placement="top"
title='Tell the AI be concise.'>
<input type="checkbox" id="concise" name="concise" value="concise" checked="false">
<label for="concise"> Be Concise</label>
</div>
</div>
<hr>
<div id="token-count" class="mb-3">Token count: 0</div>
<div id="alert-container"></div>
<button type="submit" id="send-btn" class="btn btn-primary">Summarize</button>
<div class="lds-dual-ring" id="spinner" style="display:none"></div>
</div>
</form>
<h2 class="my-4">Summary:</h2>
<div id="summary" class="border rounded p-3"></div>
</div>
<script>
// TODO: same model and token logic as backend
const MAX_TOKENS = 8100;
const SERVER_URL = "http://127.0.0.1:5000";
function debounce(func, wait) {
let timeout;
return function (...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
function showAlert(message, type = "danger") {
const alertContainer = document.getElementById("alert-container");
const alertElement = document.createElement("div");
alertElement.className = `alert alert-${type} alert-dismissible fade show`;
alertElement.textContent = message;
const closeButton = document.createElement("button");
closeButton.type = "button";
closeButton.className = "btn-close";
closeButton.setAttribute("data-bs-dismiss", "alert");
closeButton.setAttribute("aria-label", "Close");
alertElement.appendChild(closeButton);
alertContainer.appendChild(alertElement);
}
function clearAlerts() {
const alertContainer = document.getElementById("alert-container");
alertContainer.innerHTML = "";
}
const updateTokenCount = debounce(async (e) => {
const text = document.getElementById("text").value;
if (text == "" || text.length == 0 || text == null) {
return;
}
const response = await fetch(SERVER_URL + "/count_tokens", {
method: "POST",
body: new FormData(document.getElementById("text").form),
});
if (response.ok) {
const data = await response.json();
document.getElementById("token-count").textContent = `Token count: ${data.token_count}`;
} else {
showAlert("Error: Unable to count tokens");
}
}, 500);
document.getElementById("text").addEventListener("input", updateTokenCount);
document.getElementById("summarize-form").addEventListener("submit", async (e) => {
e.preventDefault();
clearAlerts();
document.getElementById("send-btn").disabled = true;
document.getElementById("spinner").style.display = 'inline-block';
const text = document.getElementById("text").value;
const tokenCount = parseInt(document.getElementById("token-count").textContent.split(" ")[2]);
if (tokenCount > MAX_TOKENS) {
showAlert("Error: Text is too long. Please reduce the token count.");
return;
}
const response = await fetch(SERVER_URL + "/summarize", {
method: "POST",
body: new FormData(e.target),
});
if (response.ok) {
const data = await response.json();
document.getElementById("summary").textContent = data.summary;
} else {
showAlert("Error: Unable to summarize text");
}
document.getElementById("send-btn").disabled = false;
document.getElementById("spinner").style.display = 'none';
});
function init() {
document.getElementById("text").value = "";
document.getElementById("concise").checked = false;
document.getElementById("model").value = "gpt-3.5-turbo";
}
window.onload = init;
</script>
</body>
</html>