Nattapong Tapachoom commited on
Commit
5916cba
·
1 Parent(s): da68305

Enhance Gradio app with improved error handling, label mapping, and UI responsiveness

Browse files
Files changed (1) hide show
  1. app.py +255 -135
app.py CHANGED
@@ -1,6 +1,13 @@
1
  import gradio as gr
2
  from transformers import pipeline
 
 
 
 
3
 
 
 
 
4
 
5
  # รายชื่อโมเดลที่ให้เลือก
6
  MODEL_LIST = [
@@ -19,199 +26,312 @@ MODEL_LIST = [
19
  "nlptown/bert-base-multilingual-uncased-sentiment"
20
  ]
21
 
22
- from functools import lru_cache
23
-
24
  # ใช้ cache เพื่อไม่ต้องโหลดโมเดลซ้ำ
25
- @lru_cache(maxsize=2)
26
- def get_nlp(model_name):
27
- return pipeline("sentiment-analysis", model=model_name)
 
 
 
 
28
 
29
- label_map = {
30
- "LABEL_0": 0,
31
- "LABEL_1": 1,
32
- "LABEL_2": 2,
33
- "LABEL_3": 3
34
- }
35
- label_name_map = {
36
- "LABEL_0": "question",
37
- "LABEL_1": "negative",
38
- "LABEL_2": "neutral",
39
- "LABEL_3": "positive"
 
 
 
 
 
40
  }
41
 
42
- def analyze_text(text, model_name):
43
- # แยกประโยคโดยใช้ \n หรือจุด
44
- import re
45
- sentences = [s.strip() for s in re.split(r'[.\n]', text) if s.strip()]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  if not sentences:
48
- return "❗ กรุณาใส่ข้อความที่ต้องการวิเคราะห์"
49
 
50
- # สีและไอคอนสำหรับแต่ละ sentiment
51
- sentiment_style = {
52
- "positive": {"emoji": "😊", "color": "#4CAF50", "bg": "#E8F5E8"},
53
- "negative": {"emoji": "😔", "color": "#F44336", "bg": "#FFEBEE"},
54
- "neutral": {"emoji": "😐", "color": "#FF9800", "bg": "#FFF3E0"},
55
- "question": {"emoji": "❓", "color": "#2196F3", "bg": "#E3F2FD"}
56
- }
57
 
58
  results = []
59
- results.append("📊 **ผลการวิเคราะห์ความรู้สึก**\n" + "="*50 + "\n")
 
 
 
 
60
 
61
- nlp = get_nlp(model_name)
62
  for i, sentence in enumerate(sentences, 1):
63
- result = nlp(sentence)[0]
64
- label = result['label']
65
- score = result['score']
66
- code = label_map.get(label, -1)
67
- label_name = label_name_map.get(label, label)
68
- style = sentiment_style.get(label_name, {"emoji": "🔍", "color": "#666666", "bg": "#F5F5F5"})
69
- bar_length = int(score * 20)
70
- progress_bar = "█" * bar_length + "░" * (20 - bar_length)
71
- result_text = f"""
72
- 🔸 **ประโยคที่ {i}:** "{sentence}"
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
- {style['emoji']} **ผลวิเคราะห์:** {label_name.upper()} (รหัส: {code})
75
- 📈 **ความมั่นใจ:** {score:.2f} ({score*100:.1f}%)
76
- {progress_bar} {score:.2f}
77
 
78
- {'─' * 60}
79
  """
80
- results.append(result_text)
 
 
 
 
81
 
82
- # เพิ่มสรุปผลรวม
83
  total_sentences = len(sentences)
84
- results.append(f"\n📋 **สรุป:** วิเคราะห์ทั้งหมด {total_sentences} ประโยค")
85
 
86
- return "\n".join(results)
87
-
 
 
 
88
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
 
91
  with gr.Blocks(
92
  theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple", neutral_hue="gray"),
93
- css="""
94
- .gradio-container {
95
- max-width: 900px !important;
96
- margin: auto !important;
97
- background: #f4f7fa !important;
98
- border-radius: 18px !important;
99
- box-shadow: 0 4px 24px 0 #bdbdbd33;
100
- }
101
- .main-card {
102
- background: white;
103
- border-radius: 16px;
104
- box-shadow: 0 2px 12px 0 #bdbdbd22;
105
- padding: 32px 32px 24px 32px;
106
- margin: 32px 0 24px 0;
107
- }
108
- .output-markdown {
109
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
110
- }
111
- .gr-button {
112
- font-size: 1.1em;
113
- padding: 0.7em 2em;
114
- border-radius: 8px;
115
- }
116
- .gr-textbox textarea {
117
- font-size: 1.1em;
118
- min-height: 120px;
119
- }
120
- .gr-dropdown input {
121
- font-size: 1.1em;
122
- }
123
- """
124
  ) as demo:
 
125
  gr.Markdown("""
126
- <div style="text-align: center; padding: 32px 0 12px 0;">
127
- <h1 style="font-size:2.5em; margin-bottom: 0.2em; color:#3b3b6d;">🧠 Thai Sentiment Analyzer</h1>
128
- <div style="font-size:1.2em; color:#666;">AI วิเคราะห์ความรู้สึกในข้อความภาษาไทย รองรับหลายโมเดลและหลายประโยค</div>
 
 
129
  </div>
130
  """)
 
131
  with gr.Row():
132
- with gr.Column():
133
  gr.Markdown("""
134
  <div class='main-card'>
135
- <h3 style='color:#4a4a7d; margin-bottom:10px;'>� เลือกโมเดลวิเคราะห์ความรู้สึก</h3>
 
136
  </div>
137
  """)
 
138
  model_dropdown = gr.Dropdown(
139
  choices=MODEL_LIST,
140
- value="ZombitX64/MultiSent-E5",
141
- label="โมเดลที่ต้องการใช้"
 
142
  )
 
143
  gr.Markdown("""
144
- <div class='main-card' style='margin-top:18px;'>
145
- <h3 style='color:#4a4a7d; margin-bottom:10px;'>� ตัวอย่างข้อความ</h3>
 
 
 
 
 
 
146
  </div>
147
  """)
148
- with gr.Column():
 
149
  gr.Markdown("""
150
  <div class='main-card'>
151
- <h3 style='color:#4a4a7d; margin-bottom:10px;'>📝 ข้อความที่ต้องการวิเคราะห์</h3>
152
- <div style='color:#888; font-size:1em;'>
153
- 💬 พิมพ์ข้อความหลายประโยคที่นี่<br>
154
- <span style='font-size:0.95em;'>• แยกแต่ละประโยคด้วยจุด (.) หรือขึ้นบรรทัดใหม่<br>• รองรับข้อความภาษาไทยและหลายประโยคพร้อมกัน</span>
155
- </div>
156
  </div>
157
  """)
 
158
  text_input = gr.Textbox(
159
- lines=7,
160
- placeholder="ตัวอย่าง: วันนี้อากาศดีมาก. ฉันมีความสุขมาก\nหรือ\nวันนี้อากาศดีมาก\nฉันมีความสุขมาก",
161
- label=""
 
162
  )
163
- analyze_btn = gr.Button("� วิเคราะห์ข้อความ", elem_id="analyze-btn")
 
 
 
 
164
  output_box = gr.Textbox(
165
  label="📊 ผลการวิเคราะห์ความรู้สึก",
166
- lines=15,
167
- show_copy_button=True
 
168
  )
169
- # ต้องสร้างตัวอย่างหลัง text_input ถูกนิยามแล้ว
170
- examples = gr.Examples(
171
- examples=[
172
- ["วันนี้อากาศดีมาก ฉันรู้สึกมีความสุขมาก"],
173
- ["ฉันไม่ชอบอาหารนี้ รสชาติแปลกมาก"],
174
- ["วันนี้เป็นยังไง\nเรียนหนังสือกันไหม"],
175
- ["บริการดีมาก พนักงานใจดี\nแต่ของมีราคาแพงไปหน่อย\nโดยรวมแล้วพอใจ"]
176
- ],
177
- inputs=[text_input],
178
- label="คลิกเพื่อใส่ตัวอย่างในกล่องข้อความ"
179
- )
 
 
 
 
180
  gr.Markdown("""
181
- <div class='main-card' style='margin-top:24px; background: #f8f9fa;'>
182
- <div style="display: flex; justify-content: space-around; padding: 10px 0;">
183
- <div style="text-align: center;">
184
- <div style="font-size: 24px;">😊</div>
185
- <strong>Positive</strong><br>
186
- <small>ความรู้สึกเชิงบวก</small>
 
187
  </div>
188
- <div style="text-align: center;">
189
- <div style="font-size: 24px;">😔</div>
190
- <strong>Negative</strong><br>
191
- <small>ความรู้สึกเชิงลบ</small>
192
  </div>
193
- <div style="text-align: center;">
194
- <div style="font-size: 24px;">😐</div>
195
- <strong>Neutral</strong><br>
196
- <small>ความรู้สึกเป็นกลาง</small>
197
  </div>
198
- <div style="text-align: center;">
199
- <div style="font-size: 24px;">❓</div>
200
- <strong>Question</strong><br>
201
- <small>ประโยคคำถาม</small>
202
  </div>
203
  </div>
204
  </div>
205
  """)
206
 
 
207
  def analyze_wrapper(text, model_name):
 
 
208
  return analyze_text(text, model_name)
 
 
 
 
 
209
  analyze_btn.click(analyze_wrapper, inputs=[text_input, model_dropdown], outputs=output_box)
210
  text_input.submit(analyze_wrapper, inputs=[text_input, model_dropdown], outputs=output_box)
211
-
212
  model_dropdown.change(analyze_wrapper, inputs=[text_input, model_dropdown], outputs=output_box)
 
213
 
214
- # เรียกใช้งาน Gradio app
215
- demo.queue().launch()
216
-
217
-
 
 
 
 
 
 
 
1
  import gradio as gr
2
  from transformers import pipeline
3
+ import re
4
+ from functools import lru_cache
5
+ import logging
6
+ from typing import List, Dict, Tuple
7
 
8
+ # Set up logging
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
 
12
  # รายชื่อโมเดลที่ให้เลือก
13
  MODEL_LIST = [
 
26
  "nlptown/bert-base-multilingual-uncased-sentiment"
27
  ]
28
 
 
 
29
  # ใช้ cache เพื่อไม่ต้องโหลดโมเดลซ้ำ
30
+ @lru_cache(maxsize=3)
31
+ def get_nlp(model_name: str):
32
+ try:
33
+ return pipeline("sentiment-analysis", model=model_name)
34
+ except Exception as e:
35
+ logger.error(f"Error loading model {model_name}: {e}")
36
+ raise gr.Error(f"ไม่สามารถโหลดโมเดล {model_name} ได้: {str(e)}")
37
 
38
+ # Enhanced label mapping with more comprehensive support
39
+ LABEL_MAPPINGS = {
40
+ # Standard labels
41
+ "LABEL_0": {"code": 0, "name": "question", "emoji": "❓", "color": "#2196F3", "bg": "#E3F2FD"},
42
+ "LABEL_1": {"code": 1, "name": "negative", "emoji": "😔", "color": "#F44336", "bg": "#FFEBEE"},
43
+ "LABEL_2": {"code": 2, "name": "neutral", "emoji": "😐", "color": "#FF9800", "bg": "#FFF3E0"},
44
+ "LABEL_3": {"code": 3, "name": "positive", "emoji": "😊", "color": "#4CAF50", "bg": "#E8F5E8"},
45
+
46
+ # Alternative label formats
47
+ "POSITIVE": {"code": 3, "name": "positive", "emoji": "😊", "color": "#4CAF50", "bg": "#E8F5E8"},
48
+ "NEGATIVE": {"code": 1, "name": "negative", "emoji": "😔", "color": "#F44336", "bg": "#FFEBEE"},
49
+ "NEUTRAL": {"code": 2, "name": "neutral", "emoji": "😐", "color": "#FF9800", "bg": "#FFF3E0"},
50
+
51
+ # Numerical labels
52
+ "0": {"code": 0, "name": "negative", "emoji": "😔", "color": "#F44336", "bg": "#FFEBEE"},
53
+ "1": {"code": 1, "name": "positive", "emoji": "😊", "color": "#4CAF50", "bg": "#E8F5E8"},
54
  }
55
 
56
+ def get_label_info(label: str) -> Dict:
57
+ """Get label information with fallback for unknown labels"""
58
+ return LABEL_MAPPINGS.get(label, {
59
+ "code": -1,
60
+ "name": label.lower(),
61
+ "emoji": "🔍",
62
+ "color": "#666666",
63
+ "bg": "#F5F5F5"
64
+ })
65
+
66
+ def split_sentences(text: str) -> List[str]:
67
+ """Enhanced sentence splitting with better Thai support"""
68
+ # Split by various sentence endings and normalize
69
+ sentences = re.split(r'[.!?。\n]+', text)
70
+ # Clean and filter empty sentences
71
+ sentences = [s.strip() for s in sentences if s.strip() and len(s.strip()) > 2]
72
+ return sentences
73
+
74
+ def create_progress_bar(score: float, width: int = 20) -> str:
75
+ """Create a visual progress bar"""
76
+ filled = int(score * width)
77
+ return "█" * filled + "░" * (width - filled)
78
+
79
+ def analyze_text(text: str, model_name: str) -> str:
80
+ """Enhanced text analysis with better error handling and formatting"""
81
+ if not text or not text.strip():
82
+ return "❗ กรุณาใส่ข้อความที่ต้องการวิเคราะห์"
83
+
84
+ sentences = split_sentences(text)
85
 
86
  if not sentences:
87
+ return "❗ ไม่พบประโยคที่สามารถวิเคราะห์ได้ กรุณาใส่ข้อความที่ยาวกว่านี้"
88
 
89
+ try:
90
+ nlp = get_nlp(model_name)
91
+ except Exception as e:
92
+ return f" เกิดข้อผิดพลาดในการโหลดโมเดล: {str(e)}"
 
 
 
93
 
94
  results = []
95
+ results.append("📊 **ผลการวิเคราะห์ความรู้สึก**\n" + "="*60 + "\n")
96
+ results.append(f"🤖 **โมเดล:** {model_name}\n")
97
+
98
+ sentiment_counts = {"positive": 0, "negative": 0, "neutral": 0, "question": 0, "other": 0}
99
+ total_confidence = 0
100
 
 
101
  for i, sentence in enumerate(sentences, 1):
102
+ try:
103
+ result = nlp(sentence)[0]
104
+ label = result['label']
105
+ score = result['score']
106
+
107
+ label_info = get_label_info(label)
108
+ label_name = label_info["name"]
109
+
110
+ # Count sentiments
111
+ if label_name in sentiment_counts:
112
+ sentiment_counts[label_name] += 1
113
+ else:
114
+ sentiment_counts["other"] += 1
115
+
116
+ total_confidence += score
117
+
118
+ # Create formatted result
119
+ progress_bar = create_progress_bar(score)
120
+ confidence_percent = score * 100
121
+
122
+ result_text = f"""
123
+ 🔸 **ประโยคที่ {i}:** "{sentence[:100]}{'...' if len(sentence) > 100 else ''}"
124
 
125
+ {label_info['emoji']} **ผลวิเคราะห์:** {label_name.upper()} (รหัส: {label_info['code']})
126
+ 📈 **ความมั่นใจ:** {score:.3f} ({confidence_percent:.1f}%)
127
+ {progress_bar} {score:.3f}
128
 
129
+ {'─' * 70}
130
  """
131
+ results.append(result_text)
132
+
133
+ except Exception as e:
134
+ logger.error(f"Error analyzing sentence {i}: {e}")
135
+ results.append(f"\n❌ เกิดข้อผิดพลาดในการวิเคราะห์ประโยคที่ {i}: {str(e)}\n{'─' * 70}\n")
136
 
137
+ # Enhanced summary
138
  total_sentences = len(sentences)
139
+ avg_confidence = total_confidence / total_sentences if total_sentences > 0 else 0
140
 
141
+ summary = f"""
142
+ 📋 **สรุปผลการวิเคราะห์**
143
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
144
+ 📊 จำนวนประโยคทั้งหมด: {total_sentences} ประโยค
145
+ 📈 ความมั่นใจเฉลี่ย: {avg_confidence:.3f} ({avg_confidence*100:.1f}%)
146
 
147
+ 🎯 **การกระจายของความรู้สึก:**
148
+ """
149
+
150
+ for sentiment, count in sentiment_counts.items():
151
+ if count > 0:
152
+ percentage = (count / total_sentences) * 100
153
+ emoji = {"positive": "😊", "negative": "😔", "neutral": "😐", "question": "❓", "other": "🔍"}
154
+ summary += f" {emoji.get(sentiment, '🔍')} {sentiment.title()}: {count} ประโยค ({percentage:.1f}%)\n"
155
+
156
+ results.append(summary)
157
+
158
+ return "\n".join(results)
159
 
160
+ # Enhanced CSS with better responsiveness
161
+ CUSTOM_CSS = """
162
+ .gradio-container {
163
+ max-width: 1200px !important;
164
+ margin: auto !important;
165
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
166
+ border-radius: 20px !important;
167
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
168
+ }
169
+ .main-card {
170
+ background: rgba(255, 255, 255, 0.95);
171
+ border-radius: 16px;
172
+ box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.1);
173
+ padding: 24px;
174
+ margin: 16px 0;
175
+ backdrop-filter: blur(10px);
176
+ }
177
+ .output-markdown {
178
+ font-family: 'Segoe UI', 'Noto Sans Thai', sans-serif !important;
179
+ line-height: 1.6;
180
+ }
181
+ .gr-button {
182
+ font-size: 1.1em;
183
+ padding: 0.8em 2.5em;
184
+ border-radius: 12px;
185
+ font-weight: 600;
186
+ transition: all 0.3s ease;
187
+ }
188
+ .gr-button:hover {
189
+ transform: translateY(-2px);
190
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
191
+ }
192
+ .gr-textbox textarea {
193
+ font-size: 1.1em;
194
+ min-height: 140px;
195
+ font-family: 'Segoe UI', 'Noto Sans Thai', sans-serif;
196
+ }
197
+ .gr-dropdown input {
198
+ font-size: 1.1em;
199
+ }
200
+ """
201
 
202
+ # Enhanced Gradio interface
203
  with gr.Blocks(
204
  theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple", neutral_hue="gray"),
205
+ css=CUSTOM_CSS,
206
+ title="Thai Sentiment Analyzer - AI วิเคราะห์ความรู้สึกภาษาไทย"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  ) as demo:
208
+
209
  gr.Markdown("""
210
+ <div style="text-align: center; padding: 40px 0 20px 0;">
211
+ <h1 style="font-size:3em; margin-bottom: 0.3em; color:white; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">🧠 Thai Sentiment Analyzer</h1>
212
+ <div style="font-size:1.3em; color:rgba(255,255,255,0.9); text-shadow: 1px 1px 2px rgba(0,0,0,0.3);">
213
+ AI วิเคราะห์ความรู้สึกในข้อความภาษาไทย รองรับหลายโมเดลและหลายประโยค
214
+ </div>
215
  </div>
216
  """)
217
+
218
  with gr.Row():
219
+ with gr.Column(scale=1):
220
  gr.Markdown("""
221
  <div class='main-card'>
222
+ <h3 style='color:#4a4a7d; margin-bottom:15px; font-size:1.2em;'>🤖 เลือกโมเดลวิเคราะห์</h3>
223
+ <p style='color:#666; font-size:0.95em; margin-bottom:10px;'>เลือกโมเดล AI ที่ต้องการใช้ในการวิเคราะห์ความรู้สึก</p>
224
  </div>
225
  """)
226
+
227
  model_dropdown = gr.Dropdown(
228
  choices=MODEL_LIST,
229
+ value="ZombitX64/MultiSent-E5-Pro",
230
+ label="โมเดลที่ต้องการใช้",
231
+ info="แนะนำ: MultiSent-E5-Pro สำหรับความแม่นยำสูง"
232
  )
233
+
234
  gr.Markdown("""
235
+ <div class='main-card' style='margin-top:20px;'>
236
+ <h3 style='color:#4a4a7d; margin-bottom:15px; font-size:1.2em;'>📖 คำแนะนำการใช้งาน</h3>
237
+ <ul style='color:#666; font-size:0.95em; line-height:1.6;'>
238
+ <li>พิมพ์ข้อความภาษาไทยที่ต้องการวิเคราะห์</li>
239
+ <li>แยกประโยคด้วยจุด (.) หรือขึ้นบรรทัดใหม่</li>
240
+ <li>รองรับการวิเคราะห์หลายประโยคพร้อมกัน</li>
241
+ <li>ผลลัพธ์จะแสดงความมั่นใจและสรุปภาพรวม</li>
242
+ </ul>
243
  </div>
244
  """)
245
+
246
+ with gr.Column(scale=2):
247
  gr.Markdown("""
248
  <div class='main-card'>
249
+ <h3 style='color:#4a4a7d; margin-bottom:15px; font-size:1.2em;'>📝 ข้อความที่ต้องการวิเคราะห์</h3>
 
 
 
 
250
  </div>
251
  """)
252
+
253
  text_input = gr.Textbox(
254
+ lines=8,
255
+ placeholder="ตัวอย่าง:\nวันนี้อากาศดีมาก ฉันรู้สึกมีความสุข\nแต่การจราจรติดมาก น่าเบื่อจริงๆ\nโดยรวมแล้วก็โอเคนะ",
256
+ label="",
257
+ show_label=False
258
  )
259
+
260
+ with gr.Row():
261
+ analyze_btn = gr.Button("🔍 วิเคราะห์ข้อความ", variant="primary", size="lg")
262
+ clear_btn = gr.Button("🗑️ ล้างข้อความ", variant="secondary")
263
+
264
  output_box = gr.Textbox(
265
  label="📊 ผลการวิเคราะห์ความรู้สึก",
266
+ lines=20,
267
+ show_copy_button=True,
268
+ show_label=True
269
  )
270
+
271
+ # Enhanced examples
272
+ examples = gr.Examples(
273
+ examples=[
274
+ ["วันนี้อากาศดีมาก ฉันรู้สึกมีความสุขมาก สีฟ้าสวยจริงๆ"],
275
+ ["ฉันไม่ชอบอาหารนี้เลย รสชาติแปลกมาก เค็มเกินไป"],
276
+ ["วันนี้เป็นยังไงบ้าง\nเรียนหนังสือกันไหม\nมีงานอะไรให้ช่วยไหม"],
277
+ ["บริการดีมาก พนักงานใจดีและเป็นกันเอง\nแต่ของมีราคาแพงไปหน่อย\nโดยรวมแล้วพอใจครับ แนะนำให้เพื่อนมาลอง"],
278
+ ["เมื่อไหร่จะได้เจอกันอีก คิดถึงมากเลย\nแต่ตอนนี้ต้องทำงานหนักก่อน เพื่ออนาคตที่ดี"]
279
+ ],
280
+ inputs=[text_input],
281
+ label="💡 คลิกเพื่อลองใช้ตัวอย่าง"
282
+ )
283
+
284
+ # Sentiment legend with enhanced styling
285
  gr.Markdown("""
286
+ <div class='main-card' style='margin-top:30px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);'>
287
+ <h3 style='color:#4a4a7d; text-align:center; margin-bottom:20px;'>🎯 คำอธิบายผลการวิเคราะห์</h3>
288
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; padding: 15px 0;">
289
+ <div style="text-align: center; padding: 15px; background: rgba(76, 175, 80, 0.1); border-radius: 12px;">
290
+ <div style="font-size: 28px; margin-bottom: 8px;">😊</div>
291
+ <strong style="color: #4CAF50; font-size: 1.1em;">Positive</strong><br>
292
+ <small style="color: #666;">ความรู้สึกเชิงบวก<br>ดี, สุข, ชอบ</small>
293
  </div>
294
+ <div style="text-align: center; padding: 15px; background: rgba(244, 67, 54, 0.1); border-radius: 12px;">
295
+ <div style="font-size: 28px; margin-bottom: 8px;">😔</div>
296
+ <strong style="color: #F44336; font-size: 1.1em;">Negative</strong><br>
297
+ <small style="color: #666;">ความรู้สึกเชิงลบ<br>เศร้า, โกรธ, ไม่ชอบ</small>
298
  </div>
299
+ <div style="text-align: center; padding: 15px; background: rgba(255, 152, 0, 0.1); border-radius: 12px;">
300
+ <div style="font-size: 28px; margin-bottom: 8px;">😐</div>
301
+ <strong style="color: #FF9800; font-size: 1.1em;">Neutral</strong><br>
302
+ <small style="color: #666;">ความรู้สึกเป็นกลาง<br>ปกติ, พอใช้ได้</small>
303
  </div>
304
+ <div style="text-align: center; padding: 15px; background: rgba(33, 150, 243, 0.1); border-radius: 12px;">
305
+ <div style="font-size: 28px; margin-bottom: 8px;">❓</div>
306
+ <strong style="color: #2196F3; font-size: 1.1em;">Question</strong><br>
307
+ <small style="color: #666;">ประโยคคำถาม<br>อะไร, ไหน, เมื่อไหร่</small>
308
  </div>
309
  </div>
310
  </div>
311
  """)
312
 
313
+ # Enhanced event handlers
314
  def analyze_wrapper(text, model_name):
315
+ if not text.strip():
316
+ return "❗ กรุณาใส่ข้อความที่ต้องการวิเคราะห์"
317
  return analyze_text(text, model_name)
318
+
319
+ def clear_text():
320
+ return ""
321
+
322
+ # Connect events
323
  analyze_btn.click(analyze_wrapper, inputs=[text_input, model_dropdown], outputs=output_box)
324
  text_input.submit(analyze_wrapper, inputs=[text_input, model_dropdown], outputs=output_box)
 
325
  model_dropdown.change(analyze_wrapper, inputs=[text_input, model_dropdown], outputs=output_box)
326
+ clear_btn.click(clear_text, outputs=text_input)
327
 
328
+ # Launch with enhanced settings
329
+ if __name__ == "__main__":
330
+ demo.queue(max_size=20).launch(
331
+ server_name="0.0.0.0",
332
+ server_port=7860,
333
+ share=False, # Set to True if you want to create a public link
334
+ show_error=True,
335
+ favicon_path=None, # Add your favicon path here
336
+ ssl_verify=False
337
+ )