Spaces:
Running
on
L40S
Running
on
L40S
🎨 Redesign from AnyCoder
#9
by
angeldove
- opened
app.py
CHANGED
|
@@ -1,284 +1,314 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
#
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
with gr.Column():
|
| 245 |
-
output_audio = gr.Audio(label="Generated Song", type="filepath")
|
| 246 |
-
output_json = gr.JSON(label="Generated Info")
|
| 247 |
-
|
| 248 |
-
# # 示例按钮
|
| 249 |
-
# examples = gr.Examples(
|
| 250 |
-
# examples=[
|
| 251 |
-
# ["male, bright, rock, happy, electric guitar and drums, the bpm is 150."],
|
| 252 |
-
# ["female, warm, jazz, romantic, synthesizer and piano, the bpm is 100."]
|
| 253 |
-
# ],
|
| 254 |
-
# inputs=[description],
|
| 255 |
-
# label="Text Prompt examples"
|
| 256 |
-
# )
|
| 257 |
-
|
| 258 |
-
# examples = gr.Examples(
|
| 259 |
-
# examples=[
|
| 260 |
-
# "[intro-medium]\n\n[verse]\n在这个疯狂的世界里\n谁不渴望一点改变\n在爱情面前\n我们都显得那么不安全\n你紧紧抱着我\n告诉我再靠近一点\n别让这璀璨的夜晚白白浪费\n我那迷茫的眼睛\n看不见未来的路\n在情感消散之前\n我们对爱的渴望永不熄灭\n你给我留下一句誓言\n想知道我们的爱是否能持续到永远\n[chorus]\n\n约定在那最后的夜晚\n不管命运如何摆布\n我们的心是否依然如初\n我会穿上红衬衫\n带着摇滚的激情\n回到我们初遇的地方\n约定在那最后的夜晚\n就算全世界都变了样\n我依然坚守诺言\n铭记这一天\n你永远是我心中的爱恋\n\n[outro-medium]\n",
|
| 261 |
-
# "[intro-short]\n\n[verse]\nThrough emerald canyons where fireflies dwell\nCerulean berries kiss morning's first swell\nCrystalline dew crowns each Vitamin Dawn's confection dissolves slowly on me\nAmbrosia breezes through honeycomb vines\nNature's own candy in Fibonacci lines\n[chorus] Blueberry fruit so sweet\n takes you higher\n can't be beat\n In your lungs\n it starts to swell\n You're under its spell\n [verse] Resin of sunlight in candied retreat\nMarmalade moonbeams melt under bare feet\nNectar spirals bloom chloroplast champagne\nPhotosynthesis sings through my veins\nChlorophyll rhythms pulse warm in my blood\nThe forest's green pharmacy floods every bud[chorus] Blueberry fruit so sweet\n takes you higher\n can't be beat\n In your lungs\n it starts to swell\n You're under its spell\n feel the buzz\n ride the wave\n Limey me\n blueberry\n your mind's enslaved\n In the haze\n lose all time\n floating free\n feeling fine\n Blueberry\n fruit so sweet\n takes you higher\n can't be beat\n In your lungs\n it starts to swell\n cry\n You're under its spell\n\n[outro-short]\n",
|
| 262 |
-
# ],
|
| 263 |
-
# inputs=[lyric],
|
| 264 |
-
# label="Lyrics examples",
|
| 265 |
-
# )
|
| 266 |
-
|
| 267 |
-
# 生成按钮点击事件
|
| 268 |
-
generate_btn.click(
|
| 269 |
-
fn=generate_song,
|
| 270 |
-
inputs=[lyric, description, prompt_audio, genre, cfg_coef, temperature, gr.State(50)],
|
| 271 |
-
outputs=[output_audio, output_json]
|
| 272 |
-
)
|
| 273 |
-
generate_bgm_btn.click(
|
| 274 |
-
fn=generate_song,
|
| 275 |
-
inputs=[lyric, description, prompt_audio, genre, cfg_coef, temperature, gr.State(50), gr.State("bgm")],
|
| 276 |
-
outputs=[output_audio, output_json]
|
| 277 |
-
)
|
| 278 |
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Sentiment Analysis - Hugging Face Spaces</title>
|
| 7 |
+
<style>
|
| 8 |
+
* {
|
| 9 |
+
margin: 0;
|
| 10 |
+
padding: 0;
|
| 11 |
+
box-sizing: border-box;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
body {
|
| 15 |
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
| 16 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 17 |
+
min-height: 100vh;
|
| 18 |
+
padding: 20px;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
.container {
|
| 22 |
+
max-width: 800px;
|
| 23 |
+
margin: 0 auto;
|
| 24 |
+
background: white;
|
| 25 |
+
border-radius: 20px;
|
| 26 |
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
| 27 |
+
overflow: hidden;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
.header {
|
| 31 |
+
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
|
| 32 |
+
color: white;
|
| 33 |
+
padding: 30px;
|
| 34 |
+
text-align: center;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
.header h1 {
|
| 38 |
+
font-size: 2.5rem;
|
| 39 |
+
margin-bottom: 10px;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
.header p {
|
| 43 |
+
font-size: 1.1rem;
|
| 44 |
+
opacity: 0.9;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
.anycoder-link {
|
| 48 |
+
color: #ffd700;
|
| 49 |
+
text-decoration: none;
|
| 50 |
+
font-weight: bold;
|
| 51 |
+
transition: transform 0.2s;
|
| 52 |
+
display: inline-block;
|
| 53 |
+
margin-top: 10px;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
.anycoder-link:hover {
|
| 57 |
+
transform: scale(1.05);
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
.content {
|
| 61 |
+
padding: 40px;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
.input-section {
|
| 65 |
+
margin-bottom: 30px;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
label {
|
| 69 |
+
display: block;
|
| 70 |
+
margin-bottom: 10px;
|
| 71 |
+
font-weight: 600;
|
| 72 |
+
color: #333;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
textarea {
|
| 76 |
+
width: 100%;
|
| 77 |
+
padding: 15px;
|
| 78 |
+
border: 2px solid #e0e0e0;
|
| 79 |
+
border-radius: 10px;
|
| 80 |
+
font-size: 1rem;
|
| 81 |
+
resize: vertical;
|
| 82 |
+
min-height: 120px;
|
| 83 |
+
transition: border-color 0.3s;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
textarea:focus {
|
| 87 |
+
outline: none;
|
| 88 |
+
border-color: #667eea;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.analyze-btn {
|
| 92 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 93 |
+
color: white;
|
| 94 |
+
border: none;
|
| 95 |
+
padding: 15px 40px;
|
| 96 |
+
font-size: 1.1rem;
|
| 97 |
+
font-weight: 600;
|
| 98 |
+
border-radius: 50px;
|
| 99 |
+
cursor: pointer;
|
| 100 |
+
transition: transform 0.2s, box-shadow 0.2s;
|
| 101 |
+
display: block;
|
| 102 |
+
margin: 20px auto;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
.analyze-btn:hover {
|
| 106 |
+
transform: translateY(-2px);
|
| 107 |
+
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
.analyze-btn:disabled {
|
| 111 |
+
opacity: 0.6;
|
| 112 |
+
cursor: not-allowed;
|
| 113 |
+
transform: none;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.result-section {
|
| 117 |
+
display: none;
|
| 118 |
+
padding: 25px;
|
| 119 |
+
background: #f8f9fa;
|
| 120 |
+
border-radius: 15px;
|
| 121 |
+
margin-top: 20px;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
.result-section.show {
|
| 125 |
+
display: block;
|
| 126 |
+
animation: fadeIn 0.5s;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
@keyframes fadeIn {
|
| 130 |
+
from { opacity: 0; transform: translateY(20px); }
|
| 131 |
+
to { opacity: 1; transform: translateY(0); }
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
.result-text {
|
| 135 |
+
font-size: 1.1rem;
|
| 136 |
+
color: #555;
|
| 137 |
+
margin-bottom: 15px;
|
| 138 |
+
font-style: italic;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
.sentiment-badge {
|
| 142 |
+
display: inline-block;
|
| 143 |
+
padding: 10px 20px;
|
| 144 |
+
border-radius: 25px;
|
| 145 |
+
font-weight: 600;
|
| 146 |
+
font-size: 1.1rem;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
.sentiment-positive {
|
| 150 |
+
background: #d4edda;
|
| 151 |
+
color: #155724;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
.sentiment-negative {
|
| 155 |
+
background: #f8d7da;
|
| 156 |
+
color: #721c24;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
.confidence {
|
| 160 |
+
margin-top: 15px;
|
| 161 |
+
font-size: 1rem;
|
| 162 |
+
color: #666;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
.emoji {
|
| 166 |
+
font-size: 2rem;
|
| 167 |
+
margin-left: 10px;
|
| 168 |
+
vertical-align: middle;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
.error {
|
| 172 |
+
background: #f8d7da;
|
| 173 |
+
color: #721c24;
|
| 174 |
+
padding: 15px;
|
| 175 |
+
border-radius: 10px;
|
| 176 |
+
margin-top: 20px;
|
| 177 |
+
display: none;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
.error.show {
|
| 181 |
+
display: block;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
.loading {
|
| 185 |
+
display: none;
|
| 186 |
+
text-align: center;
|
| 187 |
+
margin: 20px 0;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
.loading.show {
|
| 191 |
+
display: block;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
.spinner {
|
| 195 |
+
border: 4px solid #f3f3f3;
|
| 196 |
+
border-top: 4px solid #667eea;
|
| 197 |
+
border-radius: 50%;
|
| 198 |
+
width: 40px;
|
| 199 |
+
height: 40px;
|
| 200 |
+
animation: spin 1s linear infinite;
|
| 201 |
+
margin: 0 auto;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
@keyframes spin {
|
| 205 |
+
0% { transform: rotate(0deg); }
|
| 206 |
+
100% { transform: rotate(360deg); }
|
| 207 |
+
}
|
| 208 |
+
</style>
|
| 209 |
+
</head>
|
| 210 |
+
<body>
|
| 211 |
+
<div class="container">
|
| 212 |
+
<div class="header">
|
| 213 |
+
<h1>🤖 Sentiment Analysis</h1>
|
| 214 |
+
<p>Analyze the sentiment of your text using AI</p>
|
| 215 |
+
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
|
| 216 |
+
Built with anycoder
|
| 217 |
+
</a>
|
| 218 |
+
</div>
|
| 219 |
+
|
| 220 |
+
<div class="content">
|
| 221 |
+
<div class="input-section">
|
| 222 |
+
<label for="textInput">Enter your text:</label>
|
| 223 |
+
<textarea id="textInput" placeholder="Type or paste your text here to analyze its sentiment..."></textarea>
|
| 224 |
+
<button class="analyze-btn" onclick="analyzeText()">Analyze Sentiment</button>
|
| 225 |
+
</div>
|
| 226 |
+
|
| 227 |
+
<div class="loading" id="loading">
|
| 228 |
+
<div class="spinner"></div>
|
| 229 |
+
<p style="margin-top: 10px; color: #666;">Analyzing...</p>
|
| 230 |
+
</div>
|
| 231 |
+
|
| 232 |
+
<div class="result-section" id="resultSection">
|
| 233 |
+
<p class="result-text" id="resultText"></p>
|
| 234 |
+
<div>
|
| 235 |
+
<span class="sentiment-badge" id="sentimentBadge"></span>
|
| 236 |
+
<span class="emoji" id="emoji"></span>
|
| 237 |
+
</div>
|
| 238 |
+
<div class="confidence" id="confidence"></div>
|
| 239 |
+
</div>
|
| 240 |
+
|
| 241 |
+
<div class="error" id="errorSection"></div>
|
| 242 |
+
</div>
|
| 243 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
|
| 245 |
+
<script>
|
| 246 |
+
async function analyzeText() {
|
| 247 |
+
const text = document.getElementById('textInput').value.trim();
|
| 248 |
+
const resultSection = document.getElementById('resultSection');
|
| 249 |
+
const errorSection = document.getElementById('errorSection');
|
| 250 |
+
const loading = document.getElementById('loading');
|
| 251 |
+
const analyzeBtn = document.querySelector('.analyze-btn');
|
| 252 |
+
|
| 253 |
+
if (!text) {
|
| 254 |
+
showError('Please enter some text to analyze');
|
| 255 |
+
return;
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
// Hide previous results and errors
|
| 259 |
+
resultSection.classList.remove('show');
|
| 260 |
+
errorSection.classList.remove('show');
|
| 261 |
+
|
| 262 |
+
// Show loading
|
| 263 |
+
loading.classList.add('show');
|
| 264 |
+
analyzeBtn.disabled = true;
|
| 265 |
+
|
| 266 |
+
try {
|
| 267 |
+
const response = await fetch('/analyze', {
|
| 268 |
+
method: 'POST',
|
| 269 |
+
headers: {
|
| 270 |
+
'Content-Type': 'application/json',
|
| 271 |
+
},
|
| 272 |
+
body: JSON.stringify({ text: text })
|
| 273 |
+
});
|
| 274 |
+
|
| 275 |
+
const data = await response.json();
|
| 276 |
+
|
| 277 |
+
if (!response.ok) {
|
| 278 |
+
throw new Error(data.error || 'Analysis failed');
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
// Show results
|
| 282 |
+
document.getElementById('resultText').textContent = `"${data.text}"`;
|
| 283 |
+
const sentimentBadge = document.getElementById('sentimentBadge');
|
| 284 |
+
sentimentBadge.textContent = data.sentiment;
|
| 285 |
+
sentimentBadge.className = `sentiment-badge sentiment-${data.sentiment.toLowerCase()}`;
|
| 286 |
+
document.getElementById('emoji').textContent = data.emoji;
|
| 287 |
+
document.getElementById('confidence').textContent = `Confidence: ${data.confidence}%`;
|
| 288 |
+
|
| 289 |
+
resultSection.classList.add('show');
|
| 290 |
+
|
| 291 |
+
} catch (error) {
|
| 292 |
+
showError(error.message);
|
| 293 |
+
} finally {
|
| 294 |
+
loading.classList.remove('show');
|
| 295 |
+
analyzeBtn.disabled = false;
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
function showError(message) {
|
| 300 |
+
const errorSection = document.getElementById('errorSection');
|
| 301 |
+
errorSection.textContent = message;
|
| 302 |
+
errorSection.classList.add('show');
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// Allow Enter key to analyze (Shift+Enter for new line)
|
| 306 |
+
document.getElementById('textInput').addEventListener('keydown', function(e) {
|
| 307 |
+
if (e.key === 'Enter' && !e.shiftKey) {
|
| 308 |
+
e.preventDefault();
|
| 309 |
+
analyzeText();
|
| 310 |
+
}
|
| 311 |
+
});
|
| 312 |
+
</script>
|
| 313 |
+
</body>
|
| 314 |
+
</html>
|