204 lines
7.1 KiB
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>
|