SongGeneration / app.py
angeldove's picture
🎨 Redesign from AnyCoder
d2a3dcb verified
raw
history blame
9.44 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sentiment Analysis - Hugging Face Spaces</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.anycoder-link {
color: #ffd700;
text-decoration: none;
font-weight: bold;
transition: transform 0.2s;
display: inline-block;
margin-top: 10px;
}
.anycoder-link:hover {
transform: scale(1.05);
}
.content {
padding: 40px;
}
.input-section {
margin-bottom: 30px;
}
label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: #333;
}
textarea {
width: 100%;
padding: 15px;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 1rem;
resize: vertical;
min-height: 120px;
transition: border-color 0.3s;
}
textarea:focus {
outline: none;
border-color: #667eea;
}
.analyze-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 40px;
font-size: 1.1rem;
font-weight: 600;
border-radius: 50px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
display: block;
margin: 20px auto;
}
.analyze-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}
.analyze-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.result-section {
display: none;
padding: 25px;
background: #f8f9fa;
border-radius: 15px;
margin-top: 20px;
}
.result-section.show {
display: block;
animation: fadeIn 0.5s;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.result-text {
font-size: 1.1rem;
color: #555;
margin-bottom: 15px;
font-style: italic;
}
.sentiment-badge {
display: inline-block;
padding: 10px 20px;
border-radius: 25px;
font-weight: 600;
font-size: 1.1rem;
}
.sentiment-positive {
background: #d4edda;
color: #155724;
}
.sentiment-negative {
background: #f8d7da;
color: #721c24;
}
.confidence {
margin-top: 15px;
font-size: 1rem;
color: #666;
}
.emoji {
font-size: 2rem;
margin-left: 10px;
vertical-align: middle;
}
.error {
background: #f8d7da;
color: #721c24;
padding: 15px;
border-radius: 10px;
margin-top: 20px;
display: none;
}
.error.show {
display: block;
}
.loading {
display: none;
text-align: center;
margin: 20px 0;
}
.loading.show {
display: block;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 Sentiment Analysis</h1>
<p>Analyze the sentiment of your text using AI</p>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
Built with anycoder
</a>
</div>
<div class="content">
<div class="input-section">
<label for="textInput">Enter your text:</label>
<textarea id="textInput" placeholder="Type or paste your text here to analyze its sentiment..."></textarea>
<button class="analyze-btn" onclick="analyzeText()">Analyze Sentiment</button>
</div>
<div class="loading" id="loading">
<div class="spinner"></div>
<p style="margin-top: 10px; color: #666;">Analyzing...</p>
</div>
<div class="result-section" id="resultSection">
<p class="result-text" id="resultText"></p>
<div>
<span class="sentiment-badge" id="sentimentBadge"></span>
<span class="emoji" id="emoji"></span>
</div>
<div class="confidence" id="confidence"></div>
</div>
<div class="error" id="errorSection"></div>
</div>
</div>
<script>
async function analyzeText() {
const text = document.getElementById('textInput').value.trim();
const resultSection = document.getElementById('resultSection');
const errorSection = document.getElementById('errorSection');
const loading = document.getElementById('loading');
const analyzeBtn = document.querySelector('.analyze-btn');
if (!text) {
showError('Please enter some text to analyze');
return;
}
// Hide previous results and errors
resultSection.classList.remove('show');
errorSection.classList.remove('show');
// Show loading
loading.classList.add('show');
analyzeBtn.disabled = true;
try {
const response = await fetch('/analyze', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: text })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Analysis failed');
}
// Show results
document.getElementById('resultText').textContent = `"${data.text}"`;
const sentimentBadge = document.getElementById('sentimentBadge');
sentimentBadge.textContent = data.sentiment;
sentimentBadge.className = `sentiment-badge sentiment-${data.sentiment.toLowerCase()}`;
document.getElementById('emoji').textContent = data.emoji;
document.getElementById('confidence').textContent = `Confidence: ${data.confidence}%`;
resultSection.classList.add('show');
} catch (error) {
showError(error.message);
} finally {
loading.classList.remove('show');
analyzeBtn.disabled = false;
}
}
function showError(message) {
const errorSection = document.getElementById('errorSection');
errorSection.textContent = message;
errorSection.classList.add('show');
}
// Allow Enter key to analyze (Shift+Enter for new line)
document.getElementById('textInput').addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
analyzeText();
}
});
</script>
</body>
</html>