TextSummarizer / index.html
SamuelWHS's picture
Update index.html
dc1c3d9 verified
Raw History Blame Contribute Delete
13.3 kB
<!-- <!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>My static Space</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="card">
<h1>Welcome to your static Space!</h1>
<p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
<p>
Also don't forget to check the
<a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
</p>
</div>
</body>
</html> -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI Text Summarization</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: #f5f5f5;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.card {
background: white;
border-radius: 8px;
padding: 32px 40px;
max-width: 680px;
width: 100%;
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
border: 1px solid #e8e8e8;
}
h1 {
color: #1a1a1a;
font-size: 1.6rem;
font-weight: 600;
margin-bottom: 4px;
letter-spacing: -0.3px;
}
.subtitle {
color: #666;
font-size: 0.9rem;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid #eee;
font-weight: 400;
}
.model-status {
margin: -8px 0 20px 0;
padding: 8px 0;
font-size: 0.85rem;
color: #2d7a3a;
font-weight: 400;
}
.model-status.loading {
color: #b45309;
}
.model-status.error {
color: #b91c1c;
}
.input-group {
margin-bottom: 16px;
}
.input-group label {
display: block;
font-weight: 500;
color: #333;
margin-bottom: 6px;
font-size: 0.9rem;
}
textarea {
width: 100%;
padding: 10px 12px;
border: 1px solid #d0d0d0;
border-radius: 4px;
font-size: 14px;
font-family: inherit;
resize: vertical;
transition: border-color 0.2s;
min-height: 120px;
background: white;
color: #333;
line-height: 1.5;
}
textarea:focus {
outline: none;
border-color: #4a6cf7;
}
textarea::placeholder {
color: #999;
}
.output-group {
margin-bottom: 16px;
}
.output-group label {
display: block;
font-weight: 500;
color: #333;
margin-bottom: 6px;
font-size: 0.9rem;
}
#outputText {
background: #fafafa;
padding: 10px 12px;
border-radius: 4px;
min-height: 80px;
border: 1px solid #e8e8e8;
color: #333;
white-space: pre-wrap;
word-wrap: break-word;
font-size: 14px;
line-height: 1.5;
}
#outputText .placeholder {
color: #999;
}
#outputText.error {
color: #b91c1c;
}
#outputText.loading {
color: #4a6cf7;
}
.button-group {
display: flex;
gap: 10px;
margin-top: 4px;
}
button {
padding: 8px 24px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
border: 1px solid transparent;
background: transparent;
}
.submit-btn {
background: #4a6cf7;
color: white;
border-color: #4a6cf7;
order: 2;
margin-left: auto;
}
.submit-btn:hover:not(:disabled) {
background: #3b5de7;
border-color: #3b5de7;
}
.submit-btn:disabled {
background: #a0aec0;
border-color: #a0aec0;
cursor: not-allowed;
}
.clear-btn {
color: #4a5568;
border-color: #d0d0d0;
background: white;
order: 1;
}
.clear-btn:hover:not(:disabled) {
background: #f7fafc;
border-color: #a0aec0;
}
.clear-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.token-info {
margin-top: 8px;
font-size: 0.8rem;
color: #999;
text-align: right;
}
@media (max-width: 600px) {
.card {
padding: 20px;
}
h1 {
font-size: 1.3rem;
}
.button-group {
flex-wrap: wrap;
}
.submit-btn {
flex: 1;
}
.clear-btn {
flex: 0.4;
min-width: 80px;
}
}
</style>
</head>
<body>
<div class="card">
<h1>AI Text summarization</h1>
<div class="subtitle">Powered by FalconsAI T5 Sequence-to-Sequence model.</div>
<!-- Model status - styled to blend in, not stand out -->
<div id="modelStatus" class="model-status loading">⏳ Loading model...</div>
<div class="input-group">
<label for="inputText">Input text to summarize:</label>
<textarea
id="inputText"
rows="6"
placeholder="Paste document text here..."
></textarea>
</div>
<div class="output-group">
<label for="outputText">Summarized text:</label>
<div id="outputText"><span class="placeholder">Your summary will appear here...</span></div>
<div id="tokenInfo" class="token-info"></div>
</div>
<div class="button-group">
<button id="clearButton" class="clear-btn" disabled>Clear</button>
<button id="summarizeButton" class="submit-btn" disabled>Submit</button>
</div>
</div>
<!-- Use the official @huggingface/transformers import map -->
<script type="importmap">
{
"imports": {
"@huggingface/transformers": "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0/dist/transformers.min.js"
}
}
</script>
<script type="module">
import { pipeline } from '@huggingface/transformers';
// DOM elements
const inputText = document.getElementById('inputText');
const outputText = document.getElementById('outputText');
const tokenInfo = document.getElementById('tokenInfo');
const summarizeBtn = document.getElementById('summarizeButton');
const clearBtn = document.getElementById('clearButton');
const modelStatus = document.getElementById('modelStatus');
// Initialize the summarization pipeline
let summarizer = null;
let isModelReady = false;
async function initModel() {
try {
modelStatus.textContent = '⏳ Loading model...';
modelStatus.className = 'model-status loading';
summarizeBtn.disabled = true;
clearBtn.disabled = true;
summarizer = await pipeline(
'summarization',
'onnx-community/text_summarization-ONNX'
);
isModelReady = true;
modelStatus.textContent = 'βœ… Model loaded successfully! Ready to summarize.';
modelStatus.className = 'model-status';
summarizeBtn.disabled = false;
clearBtn.disabled = false;
console.log('βœ… FalconsAI summarization model loaded successfully!');
} catch (error) {
console.error('Failed to load model:', error);
modelStatus.textContent = '❌ Failed to load model. Please refresh the page.';
modelStatus.className = 'model-status error';
summarizeBtn.disabled = true;
clearBtn.disabled = true;
outputText.textContent = 'Failed to load the summarization model. Please refresh the page.';
outputText.className = 'error';
}
}
// Main summarize function - MATCHES PYTHON APP.PY DEFAULTS
async function summarize() {
if (!isModelReady || !summarizer) {
outputText.textContent = 'Model is still loading. Please wait...';
outputText.className = 'error';
return;
}
const text = inputText.value.trim();
// Check if input is empty or only whitespace
if (!text) {
outputText.textContent = 'Please enter document text to summarize.';
outputText.className = 'error';
tokenInfo.textContent = '';
return;
}
// Approximate token count using words
const inputTokens = text.split(/\s+/).length;
// Check if word count is less than 5
if (inputTokens < 5) {
outputText.textContent = 'Insufficient text to summarize.';
outputText.className = 'error';
tokenInfo.textContent = `Input tokens: ${inputTokens}`;
return;
}
// Show loading state
outputText.textContent = 'Summarizing...';
outputText.className = 'loading';
summarizeBtn.disabled = true;
tokenInfo.textContent = '';
try {
// Proceed with summarization - MATCH PYTHON DEFAULTS
const result = await summarizer(text, {
truncation: true,
max_length: 200, // Python default: 200
min_length: 50, // Python default: 50
do_sample: false, // Python default: False
num_beams: 4, // Python default: 4 beams
early_stopping: true
});
// Get summary text
const summaryText = result[0].summary_text;
// Calculate output tokens (approximate using word count)
const outputTokens = summaryText.split(/\s+/).length;
// Debug print statement (visible in browser console)
console.log(`Input tokens: ${inputTokens}, Output tokens: ${outputTokens}`);
// Update UI
outputText.textContent = summaryText;
outputText.className = '';
tokenInfo.textContent = `Input tokens: ${inputTokens} | Output tokens: ${outputTokens}`;
} catch (error) {
console.error('Summarization error:', error);
outputText.textContent = `An error occurred: ${error.message || 'Unknown error'}`;
outputText.className = 'error';
} finally {
summarizeBtn.disabled = false;
}
}
// Clear function
function clearAll() {
inputText.value = '';
outputText.innerHTML = '<span class="placeholder">Your summary will appear here...</span>';
outputText.className = '';
tokenInfo.textContent = '';
}
// Event listeners
summarizeBtn.addEventListener('click', summarize);
clearBtn.addEventListener('click', clearAll);
// Allow Ctrl+Enter to summarize (same as your Python version)
inputText.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
summarize();
}
});
// Initialize the model when the page loads
console.log('πŸš€ Loading FalconsAI summarization model...');
initModel();
</script>
</body>
</html>