JonusNattapong commited on
Commit
e8fd6ae
·
verified ·
1 Parent(s): 4282022

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -81
app.py CHANGED
@@ -39,29 +39,94 @@ def get_nlp(model_name: str):
39
  logger.error(f"Error loading model {model_name}: {e}")
40
  raise gr.Error(f"ไม่สามารถโหลดโมเดล {model_name} ได้: {str(e)}")
41
 
42
- # Enhanced label mapping with modern styling for dark blue theme
43
- LABEL_MAPPINGS = {
44
- "LABEL_0": {"code": 0, "name": "question", "emoji": "🤔", "color": "#ef4444", "bg": "rgba(239, 68, 68, 0.2)", "description": "เชิงลบมาก"},
45
- "LABEL_1": {"code": 1, "name": "negative", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"},
46
- "LABEL_2": {"code": 2, "name": "neutral", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"},
47
- "LABEL_3": {"code": 3, "name": "positive", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"},
48
-
49
- "0": {"code": 0, "name": "negative", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"},
50
- "1": {"code": 1, "name": "neutral", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"},
51
- "2": {"code": 2, "name": "positive", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
 
 
 
 
 
 
 
 
 
53
  }
54
 
55
  def get_label_info(label: str) -> Dict:
56
- """Get label information with fallback for unknown labels"""
57
- return LABEL_MAPPINGS.get(label, {
58
- "code": -1,
59
- "name": label.lower(),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  "emoji": "🔍",
61
  "color": "#64748b",
62
  "bg": "rgba(100, 116, 139, 0.2)",
63
- "description": "ไม่ทราบ"
64
- })
65
 
66
  def split_sentences(text: str) -> List[str]:
67
  """Enhanced sentence splitting with better Thai support"""
@@ -82,7 +147,7 @@ def create_confidence_bar(score: float) -> str:
82
  """
83
 
84
  def analyze_text(text: str, model_name: str) -> str:
85
- """Enhanced text analysis with modern HTML formatting"""
86
  if not text or not text.strip():
87
  return """
88
  <div style="padding: 20px; background: rgba(248, 113, 113, 0.2); border-radius: 12px; border-left: 4px solid #f87171;">
@@ -128,18 +193,11 @@ def analyze_text(text: str, model_name: str) -> str:
128
  </div>
129
  """]
130
 
131
- # Updated sentiment_counts to include all 5 sentiment levels plus question
132
- sentiment_counts = {
133
- "question": 0,
134
- "very negative": 0,
135
- "negative": 0,
136
- "neutral": 0,
137
- "positive": 0,
138
- "very positive": 0,
139
- "other": 0
140
- }
141
  total_confidence = 0
142
  sentence_results = []
 
143
 
144
  # Analyze each sentence
145
  for i, sentence in enumerate(sentences, 1):
@@ -148,14 +206,17 @@ def analyze_text(text: str, model_name: str) -> str:
148
  label = result['label']
149
  score = result['score']
150
 
 
 
 
151
  label_info = get_label_info(label)
152
- label_name = label_info["name"]
153
 
154
- # Increment count for the corresponding sentiment name
155
- if label_name in sentiment_counts:
156
- sentiment_counts[label_name] += 1
157
  else:
158
- sentiment_counts["other"] += 1
159
 
160
  total_confidence += score
161
 
@@ -164,7 +225,8 @@ def analyze_text(text: str, model_name: str) -> str:
164
  'sentence': sentence,
165
  'label_info': label_info,
166
  'score': score,
167
- 'index': i
 
168
  })
169
 
170
  except Exception as e:
@@ -207,6 +269,9 @@ def analyze_text(text: str, model_name: str) -> str:
207
  <span style="background: {label_info['color']}; color: #f8fafc; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; text-transform: uppercase;">
208
  {label_info['description']}
209
  </span>
 
 
 
210
  <span style="color: #94a3b8; font-size: 14px;">ประโยคที่ {result['index']}</span>
211
  </div>
212
  <p style="color: #f8fafc; margin: 0 0 12px 0; font-size: 16px; line-height: 1.5;">
@@ -223,55 +288,35 @@ def analyze_text(text: str, model_name: str) -> str:
223
  total_sentences = len(sentences)
224
  avg_confidence = total_confidence / total_sentences if total_sentences > 0 else 0
225
 
226
- # Create chart data for summary
227
  chart_items = []
228
- # Ensure colors and emojis include all 6 categories (question + 5 sentiments)
229
- colors = {
230
- "question": "#60a5fa",
231
- "very negative": "#ef4444",
232
- "negative": "#f87171",
233
- "neutral": "#facc15",
234
- "positive": "#34d399",
235
- "very positive": "#22c55e",
236
- "other": "#64748b"
237
- }
238
- emojis = {
239
- "question": "🤔",
240
- "very negative": "😡",
241
- "negative": "😢",
242
- "neutral": "😐",
243
- "positive": "😊",
244
- "very positive": "🤩",
245
- "other": "🔍"
246
- }
247
 
248
- # Iterate through all possible sentiment types to ensure they are displayed, even if count is 0
249
- # Or, iterate through sentiment_counts.items() if you only want to display sentiments found in the text
250
- for sentiment_name, count in sentiment_counts.items():
251
- if sentiment_name == "other" and count == 0: # Don't show 'other' if no unknown labels
252
- continue
253
- if total_sentences == 0:
254
- percentage = 0
255
- else:
256
- percentage = (count / total_sentences) * 100
257
 
258
- # Get description from LABEL_MAPPINGS using the sentiment name
259
- # We can find it by iterating through LABEL_MAPPINGS values
260
- description = next((info['description'] for info in LABEL_MAPPINGS.values() if info['name'] == sentiment_name), sentiment_name)
261
-
262
  chart_items.append(f"""
263
  <div style="display: flex; align-items: center; gap: 12px; padding: 12px; background: rgba(59, 130, 246, 0.1); border-radius: 8px;">
264
- <span style="font-size: 24px;">{emojis.get(sentiment_name, '🔍')}</span>
265
  <div style="flex: 1;">
266
- <div style="font-weight: 600; color: #f8fafc; text-transform: capitalize;">{description}</div>
267
  <div style="color: #94a3b8; font-size: 14px;">{count} ประโยค ({percentage:.1f}%)</div>
268
  </div>
269
  <div style="width: 60px; height: 6px; background: #334155; border-radius: 3px; overflow: hidden;">
270
- <div style="width: {percentage}%; height: 100%; background: {colors.get(sentiment_name, '#64748b')}; transition: all 0.3s ease;"></div>
271
  </div>
272
  </div>
273
  """)
274
 
 
 
 
275
  html_parts.append(f"""
276
  <div style="padding: 24px; background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);">
277
  <h3 style="color: #f8fafc; margin: 0 0 20px 0; font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 8px;">
@@ -290,9 +335,14 @@ def analyze_text(text: str, model_name: str) -> str:
290
  </div>
291
  </div>
292
 
293
- <div style="display: grid; gap: 8px;">
294
  {"".join(chart_items)}
295
  </div>
 
 
 
 
 
296
  </div>
297
  """)
298
 
@@ -433,8 +483,8 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Base()) as demo:
433
  with gr.Row():
434
  gr.HTML("""
435
  <div class='main-uxui-header'>
436
- <h1>Thai Sentiment Analysis (SpaceThai-e5)</h1>
437
- <p>วิเคราะห์ความรู้สึกภาษาไทย/อังกฤษ รองรับหลายโมเดล | Modern UX/UI</p>
438
  </div>
439
  """)
440
  with gr.Row():
@@ -462,8 +512,10 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Base()) as demo:
462
  ["เศร้ามากเลยวันนี้ งานเยอะเกินไป"],
463
  ["อาหารอร่อยดี แต่บริการช้ามาก"],
464
  ["คุณคิดอย่างไรกับเศรษฐกิจไทย?"],
465
- ["I love this product! It's amazing."],
466
- ["This is the worst experience I've ever had."]
 
 
467
  ],
468
  inputs=input_box,
469
  label="ตัวอย่างข้อความ",
@@ -472,15 +524,25 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Base()) as demo:
472
  gr.HTML("""
473
  <div class='main-uxui-legend'>
474
  <div class='main-uxui-section-title'>
475
- <span>🗂️</span> คำอธิบายผลลัพธ์
476
  </div>
477
  <div class='legend-row'>
478
- <div class='legend-item'><strong>🤩 เชิงบวกมาก</strong><br><small>Very Positive</small></div>
479
- <div class='legend-item'><strong>😊 เชิงบวก</strong><br><small>Positive</small></div>
480
- <div class='legend-item'><strong>😐 เป็นกลาง</strong><br><small>Neutral</small></div>
481
- <div class='legend-item'><strong>😢 เชิงลบ</strong><br><small>Negative</small></div>
482
- <div class='legend-item'><strong>😡 เชิงลบมาก</strong><br><small>Very Negative</small></div>
483
- <div class='legend-item'><strong>🤔 คำถาม</strong><br><small>Question</small></div>
 
 
 
 
 
 
 
 
 
 
484
  </div>
485
  </div>
486
  """)
 
39
  logger.error(f"Error loading model {model_name}: {e}")
40
  raise gr.Error(f"ไม่สามารถโหลดโมเดล {model_name} ได้: {str(e)}")
41
 
42
+ # Comprehensive label mapping system that covers multiple model formats
43
+ COMPREHENSIVE_LABEL_MAPPINGS = {
44
+ # Standard format labels (LABEL_X)
45
+ "LABEL_0": {"sentiment": "negative", "intensity": "normal", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"},
46
+ "LABEL_1": {"sentiment": "neutral", "intensity": "normal", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"},
47
+ "LABEL_2": {"sentiment": "positive", "intensity": "normal", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"},
48
+ "LABEL_3": {"sentiment": "very_positive", "intensity": "high", "emoji": "🤩", "color": "#22c55e", "bg": "rgba(34, 197, 94, 0.2)", "description": "เชิงบวกมาก"},
49
+ "LABEL_4": {"sentiment": "question", "intensity": "normal", "emoji": "🤔", "color": "#60a5fa", "bg": "rgba(96, 165, 250, 0.2)", "description": "คำถาม"},
50
+
51
+ # Numeric format labels (0, 1, 2, etc.)
52
+ "0": {"sentiment": "negative", "intensity": "normal", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"},
53
+ "1": {"sentiment": "neutral", "intensity": "normal", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"},
54
+ "2": {"sentiment": "positive", "intensity": "normal", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"},
55
+ "3": {"sentiment": "very_positive", "intensity": "high", "emoji": "🤩", "color": "#22c55e", "bg": "rgba(34, 197, 94, 0.2)", "description": "เชิงบวกมาก"},
56
+ "4": {"sentiment": "question", "intensity": "normal", "emoji": "🤔", "color": "#60a5fa", "bg": "rgba(96, 165, 250, 0.2)", "description": "คำถาม"},
57
+
58
+ # Extended range for models with more classes
59
+ "5": {"sentiment": "very_negative", "intensity": "high", "emoji": "😡", "color": "#ef4444", "bg": "rgba(239, 68, 68, 0.2)", "description": "เชิงลบมาก"},
60
+ "LABEL_5": {"sentiment": "very_negative", "intensity": "high", "emoji": "😡", "color": "#ef4444", "bg": "rgba(239, 68, 68, 0.2)", "description": "เชิงลบมาก"},
61
+
62
+ # Text-based labels (common in some models)
63
+ "NEGATIVE": {"sentiment": "negative", "intensity": "normal", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"},
64
+ "NEUTRAL": {"sentiment": "neutral", "intensity": "normal", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"},
65
+ "POSITIVE": {"sentiment": "positive", "intensity": "normal", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"},
66
+ "VERY_NEGATIVE": {"sentiment": "very_negative", "intensity": "high", "emoji": "😡", "color": "#ef4444", "bg": "rgba(239, 68, 68, 0.2)", "description": "เชิงลบมาก"},
67
+ "VERY_POSITIVE": {"sentiment": "very_positive", "intensity": "high", "emoji": "🤩", "color": "#22c55e", "bg": "rgba(34, 197, 94, 0.2)", "description": "เชิงบวกมาก"},
68
+ "QUESTION": {"sentiment": "question", "intensity": "normal", "emoji": "🤔", "color": "#60a5fa", "bg": "rgba(96, 165, 250, 0.2)", "description": "คำถาม"},
69
+
70
+ # Lowercase variants
71
+ "negative": {"sentiment": "negative", "intensity": "normal", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"},
72
+ "neutral": {"sentiment": "neutral", "intensity": "normal", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"},
73
+ "positive": {"sentiment": "positive", "intensity": "normal", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"},
74
+ "very_negative": {"sentiment": "very_negative", "intensity": "high", "emoji": "😡", "color": "#ef4444", "bg": "rgba(239, 68, 68, 0.2)", "description": "เชิงลบมาก"},
75
+ "very_positive": {"sentiment": "very_positive", "intensity": "high", "emoji": "🤩", "color": "#22c55e", "bg": "rgba(34, 197, 94, 0.2)", "description": "เชิงบวกมาก"},
76
+ "question": {"sentiment": "question", "intensity": "normal", "emoji": "🤔", "color": "#60a5fa", "bg": "rgba(96, 165, 250, 0.2)", "description": "คำถาม"},
77
+ }
78
 
79
+ # Sentiment categories for counting and summary
80
+ SENTIMENT_CATEGORIES = {
81
+ "very_negative": {"name": "เชิงลบมาก", "emoji": "😡", "color": "#ef4444", "order": 1},
82
+ "negative": {"name": "เชิงลบ", "emoji": "😢", "color": "#f87171", "order": 2},
83
+ "neutral": {"name": "เป็นกลาง", "emoji": "😐", "color": "#facc15", "order": 3},
84
+ "positive": {"name": "เชิงบวก", "emoji": "😊", "color": "#34d399", "order": 4},
85
+ "very_positive": {"name": "เชิงบวกมาก", "emoji": "🤩", "color": "#22c55e", "order": 5},
86
+ "question": {"name": "คำถาม", "emoji": "🤔", "color": "#60a5fa", "order": 6},
87
+ "unknown": {"name": "ไม่ทราบ", "emoji": "🔍", "color": "#64748b", "order": 7}
88
  }
89
 
90
  def get_label_info(label: str) -> Dict:
91
+ """
92
+ Enhanced label information extraction with fallback handling
93
+ Supports multiple label formats from different models
94
+ """
95
+ # Convert to string and clean
96
+ label_str = str(label).strip()
97
+
98
+ # Try exact match first
99
+ if label_str in COMPREHENSIVE_LABEL_MAPPINGS:
100
+ return COMPREHENSIVE_LABEL_MAPPINGS[label_str]
101
+
102
+ # Try case-insensitive match
103
+ label_upper = label_str.upper()
104
+ label_lower = label_str.lower()
105
+
106
+ for key, value in COMPREHENSIVE_LABEL_MAPPINGS.items():
107
+ if key.upper() == label_upper or key.lower() == label_lower:
108
+ return value
109
+
110
+ # Try pattern matching for complex labels
111
+ if re.match(r'^LABEL_\d+$', label_str, re.IGNORECASE):
112
+ # Extract number from LABEL_X format
113
+ try:
114
+ num = int(re.findall(r'\d+', label_str)[0])
115
+ if str(num) in COMPREHENSIVE_LABEL_MAPPINGS:
116
+ return COMPREHENSIVE_LABEL_MAPPINGS[str(num)]
117
+ except (IndexError, ValueError):
118
+ pass
119
+
120
+ # Fallback for unknown labels
121
+ logger.warning(f"Unknown label: {label}")
122
+ return {
123
+ "sentiment": "unknown",
124
+ "intensity": "normal",
125
  "emoji": "🔍",
126
  "color": "#64748b",
127
  "bg": "rgba(100, 116, 139, 0.2)",
128
+ "description": f"ไม่ทราบ ({label})"
129
+ }
130
 
131
  def split_sentences(text: str) -> List[str]:
132
  """Enhanced sentence splitting with better Thai support"""
 
147
  """
148
 
149
  def analyze_text(text: str, model_name: str) -> str:
150
+ """Enhanced text analysis with comprehensive multi-model support"""
151
  if not text or not text.strip():
152
  return """
153
  <div style="padding: 20px; background: rgba(248, 113, 113, 0.2); border-radius: 12px; border-left: 4px solid #f87171;">
 
193
  </div>
194
  """]
195
 
196
+ # Initialize sentiment counting system
197
+ sentiment_counts = {category: 0 for category in SENTIMENT_CATEGORIES.keys()}
 
 
 
 
 
 
 
 
198
  total_confidence = 0
199
  sentence_results = []
200
+ unique_labels_found = set()
201
 
202
  # Analyze each sentence
203
  for i, sentence in enumerate(sentences, 1):
 
206
  label = result['label']
207
  score = result['score']
208
 
209
+ # Track unique labels for debugging
210
+ unique_labels_found.add(label)
211
+
212
  label_info = get_label_info(label)
213
+ sentiment_type = label_info["sentiment"]
214
 
215
+ # Count sentiment
216
+ if sentiment_type in sentiment_counts:
217
+ sentiment_counts[sentiment_type] += 1
218
  else:
219
+ sentiment_counts["unknown"] += 1
220
 
221
  total_confidence += score
222
 
 
225
  'sentence': sentence,
226
  'label_info': label_info,
227
  'score': score,
228
+ 'index': i,
229
+ 'raw_label': label
230
  })
231
 
232
  except Exception as e:
 
269
  <span style="background: {label_info['color']}; color: #f8fafc; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; text-transform: uppercase;">
270
  {label_info['description']}
271
  </span>
272
+ <span style="color: #64748b; font-size: 12px; background: #1e293b; padding: 2px 8px; border-radius: 10px;">
273
+ {result['raw_label']}
274
+ </span>
275
  <span style="color: #94a3b8; font-size: 14px;">ประโยคที่ {result['index']}</span>
276
  </div>
277
  <p style="color: #f8fafc; margin: 0 0 12px 0; font-size: 16px; line-height: 1.5;">
 
288
  total_sentences = len(sentences)
289
  avg_confidence = total_confidence / total_sentences if total_sentences > 0 else 0
290
 
291
+ # Create chart data for summary (only show categories with counts > 0 or important ones)
292
  chart_items = []
293
+ sorted_categories = sorted(
294
+ [(k, v, sentiment_counts[k]) for k, v in SENTIMENT_CATEGORIES.items()],
295
+ key=lambda x: x[1]["order"]
296
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
+ for sentiment_key, sentiment_info, count in sorted_categories:
299
+ if count == 0 and sentiment_key == "unknown":
300
+ continue # Skip unknown if no unknown sentiments
301
+
302
+ percentage = (count / total_sentences) * 100 if total_sentences > 0 else 0
 
 
 
 
303
 
 
 
 
 
304
  chart_items.append(f"""
305
  <div style="display: flex; align-items: center; gap: 12px; padding: 12px; background: rgba(59, 130, 246, 0.1); border-radius: 8px;">
306
+ <span style="font-size: 24px;">{sentiment_info['emoji']}</span>
307
  <div style="flex: 1;">
308
+ <div style="font-weight: 600; color: #f8fafc;">{sentiment_info['name']}</div>
309
  <div style="color: #94a3b8; font-size: 14px;">{count} ประโยค ({percentage:.1f}%)</div>
310
  </div>
311
  <div style="width: 60px; height: 6px; background: #334155; border-radius: 3px; overflow: hidden;">
312
+ <div style="width: {percentage}%; height: 100%; background: {sentiment_info['color']}; transition: all 0.3s ease;"></div>
313
  </div>
314
  </div>
315
  """)
316
 
317
+ # Debug information showing found labels
318
+ debug_labels = ", ".join(sorted(unique_labels_found))
319
+
320
  html_parts.append(f"""
321
  <div style="padding: 24px; background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);">
322
  <h3 style="color: #f8fafc; margin: 0 0 20px 0; font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 8px;">
 
335
  </div>
336
  </div>
337
 
338
+ <div style="display: grid; gap: 8px; margin-bottom: 16px;">
339
  {"".join(chart_items)}
340
  </div>
341
+
342
+ <div style="background: #1e293b; padding: 12px; border-radius: 8px; border-left: 4px solid #60a5fa;">
343
+ <div style="color: #60a5fa; font-size: 12px; font-weight: 600; margin-bottom: 4px;">🔍 Labels ที่พบในโมเดลนี้:</div>
344
+ <div style="color: #94a3b8; font-size: 12px; font-family: monospace;">{debug_labels}</div>
345
+ </div>
346
  </div>
347
  """)
348
 
 
483
  with gr.Row():
484
  gr.HTML("""
485
  <div class='main-uxui-header'>
486
+ <h1>Thai Sentiment Analysis (Multi-Model)</h1>
487
+ <p>วิเคราะห์ความรู้สึกภาษาไทย/อังกฤษ รองรับหลายโมเดล | Enhanced Multi-Label Support</p>
488
  </div>
489
  """)
490
  with gr.Row():
 
512
  ["เศร้ามากเลยวันนี้ งานเยอะเกินไป"],
513
  ["อาหารอร่อยดี แต่บริการช้ามาก"],
514
  ["คุณคิดอย่างไรกับเศรษฐกิจไทย?"],
515
+ ["I love this product! It's amazing and perfect!"],
516
+ ["This is the worst experience I've ever had. Absolutely terrible!"],
517
+ ["The weather is okay today, nothing special."],
518
+ ["What do you think about this new technology?"]
519
  ],
520
  inputs=input_box,
521
  label="ตัวอย่างข้อความ",
 
524
  gr.HTML("""
525
  <div class='main-uxui-legend'>
526
  <div class='main-uxui-section-title'>
527
+ <span>🗂️</span> คำอธิบายผลลัพธ์ (รองรับ Label หลายรูปแบบ)
528
  </div>
529
  <div class='legend-row'>
530
+ <div class='legend-item'><strong>😡 เชิงลบมาก</strong><br><small>Very Negative<br>Labels: 5, LABEL_5, VERY_NEGATIVE</small></div>
531
+ <div class='legend-item'><strong>😢 เชิงลบ</strong><br><small>Negative<br>Labels: 0, LABEL_0, NEGATIVE</small></div>
532
+ <div class='legend-item'><strong>😐 เป็นกลาง</strong><br><small>Neutral<br>Labels: 1, LABEL_1, NEUTRAL</small></div>
533
+ <div class='legend-item'><strong>😊 เชิงบวก</strong><br><small>Positive<br>Labels: 2, LABEL_2, POSITIVE</small></div>
534
+ <div class='legend-item'><strong>🤩 เชิงบวกมาก</strong><br><small>Very Positive<br>Labels: 3, LABEL_3, VERY_POSITIVE</small></div>
535
+ <div class='legend-item'><strong>🤔 คำถาม</strong><br><small>Question<br>Labels: 4, LABEL_4, QUESTION</small></div>
536
+ </div>
537
+ <div style="margin-top: 16px; padding: 12px; background: rgba(96, 165, 250, 0.1); border-radius: 8px; border-left: 4px solid #60a5fa;">
538
+ <div style="color: #60a5fa; font-weight: 600; margin-bottom: 8px;">✨ คุณสมบัติใหม่:</div>
539
+ <ul style="color: #94a3b8; font-size: 14px; margin: 0; padding-left: 20px;">
540
+ <li>รองรับ Label หลายรูปแบบ (LABEL_X, ตัวเลข, ข้อความ)</li>
541
+ <li>แสดง Label ดิบที่โมเดลส่งออกมา</li>
542
+ <li>ระบบ Fallback สำหรับ Label ที่ไม่รู้จัก</li>
543
+ <li>Debug information แสดง Label ที่พบ</li>
544
+ <li>การนับและสรุปผลที่แม่นยำขึ้น</li>
545
+ </ul>
546
  </div>
547
  </div>
548
  """)