Spaces:
Running
Running
import gradio as gr | |
from transformers import pipeline | |
import re | |
from functools import lru_cache | |
import logging | |
from typing import List, Dict, Tuple | |
import json | |
# Set up logging | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
# Enhanced model list with descriptions | |
MODEL_LIST = [ | |
("ZombitX64/MultiSent-E5-Pro", "🏆 MultiSent E5 Pro - แนะนำ (ความแม่นยำสูงสุด)"), | |
("ZombitX64/Thai-sentiment-e5", "🎯 Thai Sentiment E5 - เฉพาะภาษาไทย"), | |
("poom-sci/WangchanBERTa-finetuned-sentiment", "🔥 WangchanBERTa - โมเดลไทยยอดนิยม"), | |
("SandboxBhh/sentiment-thai-text-model", "✨ Sandbox Thai - เร็วและแม่นยำ"), | |
("ZombitX64/MultiSent-E5", "⚡ MultiSent E5 - รวดเร็ว"), | |
("Thaweewat/wangchanberta-hyperopt-sentiment-01", "🧠 WangchanBERTa Hyperopt"), | |
("cardiffnlp/twitter-xlm-roberta-base-sentiment", "🌐 XLM-RoBERTa - หลายภาษา"), | |
("phoner45/wangchan-sentiment-thai-text-model", "📱 Wangchan Mobile"), | |
("ZombitX64/Sentiment-01", "🔬 Sentiment v1"), | |
("ZombitX64/Sentiment-02", "🔬 Sentiment v2"), | |
("ZombitX64/Sentiment-03", "🔬 Sentiment v3"), | |
("ZombitX64/sentiment-103", "🔬 Sentiment 103"), | |
("nlptown/bert-base-multilingual-uncased-sentiment", "🌍 BERT Multilingual") | |
] | |
# Cache for model loading | |
def get_nlp(model_name: str): | |
try: | |
return pipeline("sentiment-analysis", model=model_name) | |
except Exception as e: | |
logger.error(f"Error loading model {model_name}: {e}") | |
raise gr.Error(f"ไม่สามารถโหลดโมเดล {model_name} ได้: {str(e)}") | |
# Enhanced label mapping with modern styling for dark blue theme | |
LABEL_MAPPINGS = { | |
"LABEL_0": {"code": 0, "name": "question", "emoji": "🤔", "color": "#60a5fa", "bg": "rgba(96, 165, 250, 0.2)", "description": "คำถาม"}, | |
"LABEL_1": {"code": 1, "name": "negative", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"}, | |
"LABEL_2": {"code": 2, "name": "neutral", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"}, | |
"LABEL_3": {"code": 3, "name": "positive", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"}, | |
"POSITIVE": {"code": 3, "name": "positive", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"}, | |
"NEGATIVE": {"code": 1, "name": "negative", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"}, | |
"NEUTRAL": {"code": 2, "name": "neutral", "emoji": "😐", "color": "#facc15", "bg": "rgba(250, 204, 21, 0.2)", "description": "เป็นกลาง"}, | |
"0": {"code": 0, "name": "negative", "emoji": "😢", "color": "#f87171", "bg": "rgba(248, 113, 113, 0.2)", "description": "เชิงลบ"}, | |
"1": {"code": 1, "name": "positive", "emoji": "😊", "color": "#34d399", "bg": "rgba(52, 211, 153, 0.2)", "description": "เชิงบวก"}, | |
} | |
def get_label_info(label: str) -> Dict: | |
"""Get label information with fallback for unknown labels""" | |
return LABEL_MAPPINGS.get(label, { | |
"code": -1, | |
"name": label.lower(), | |
"emoji": "🔍", | |
"color": "#64748b", | |
"bg": "rgba(100, 116, 139, 0.2)", | |
"description": "ไม่ทราบ" | |
}) | |
def split_sentences(text: str) -> List[str]: | |
"""Enhanced sentence splitting with better Thai support""" | |
sentences = re.split(r'[.!?။\n]+', text) | |
sentences = [s.strip() for s in sentences if s.strip() and len(s.strip()) > 2] | |
return sentences | |
def create_confidence_bar(score: float) -> str: | |
"""Create a modern confidence visualization""" | |
percentage = int(score * 100) | |
return f""" | |
<div style="display: flex; align-items: center; gap: 10px; margin: 8px 0;"> | |
<div style="flex: 1; height: 8px; background: #334155; border-radius: 4px; overflow: hidden;"> | |
<div style="width: {percentage}%; height: 100%; background: linear-gradient(90deg, #60a5fa, #3b82f6); transition: all 0.3s ease;"></div> | |
</div> | |
<span style="font-weight: 600; color: #cbd5e1; min-width: 50px;">{percentage}%</span> | |
</div> | |
""" | |
def analyze_text(text: str, model_name: str) -> str: | |
"""Enhanced text analysis with modern HTML formatting""" | |
if not text or not text.strip(): | |
return """ | |
<div style="padding: 20px; background: rgba(248, 113, 113, 0.2); border-radius: 12px; border-left: 4px solid #f87171;"> | |
<div style="color: #f87171; font-weight: 600; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 20px;">⚠️</span> | |
กรุณาใส่ข้อความที่ต้องการวิเคราะห์ | |
</div> | |
</div> | |
""" | |
sentences = split_sentences(text) | |
if not sentences: | |
return """ | |
<div style="padding: 20px; background: rgba(248, 113, 113, 0.2); border-radius: 12px; border-left: 4px solid #f87171;"> | |
<div style="color: #f87171; font-weight: 600; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 20px;">⚠️</span> | |
ไม่พบประโยคที่สามารถวิเคราะห์ได้ กรุณาใส่ข้อความที่ยาวกว่านี้ | |
</div> | |
</div> | |
""" | |
try: | |
nlp = get_nlp(model_name) | |
except Exception as e: | |
return f""" | |
<div style="padding: 20px; background: rgba(248, 113, 113, 0.2); border-radius: 12px; border-left: 4px solid #f87171;"> | |
<div style="color: #f87171; font-weight: 600; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 20px;">❌</span> | |
เกิดข้อผิดพลาดในการโหลดโมเดล: {str(e)} | |
</div> | |
</div> | |
""" | |
# Header | |
html_parts = [""" | |
<div style="background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); color: #f8fafc; padding: 24px; border-radius: 16px 16px 0 0; margin-bottom: 0;"> | |
<h2 style="margin: 0; font-size: 24px; font-weight: 700; display: flex; align-items: center; gap: 12px;"> | |
<span style="font-size: 28px;">🧠</span> | |
ผลการวิเคราะห์ความรู้สึก | |
</h2> | |
<p style="margin: 8px 0 0 0; opacity: 0.9; font-size: 14px;">โมเดล: """ + model_name.split('/')[-1] + """</p> | |
</div> | |
"""] | |
sentiment_counts = {"positive": 0, "negative": 0, "neutral": 0, "question": 0, "other": 0} | |
total_confidence = 0 | |
sentence_results = [] | |
# Analyze each sentence | |
for i, sentence in enumerate(sentences, 1): | |
try: | |
result = nlp(sentence)[0] | |
label = result['label'] | |
score = result['score'] | |
label_info = get_label_info(label) | |
label_name = label_info["name"] | |
if label_name in sentiment_counts: | |
sentiment_counts[label_name] += 1 | |
else: | |
sentiment_counts["other"] += 1 | |
total_confidence += score | |
# Store result for display | |
sentence_results.append({ | |
'sentence': sentence, | |
'label_info': label_info, | |
'score': score, | |
'index': i | |
}) | |
except Exception as e: | |
logger.error(f"Error analyzing sentence {i}: {e}") | |
sentence_results.append({ | |
'sentence': sentence, | |
'error': str(e), | |
'index': i | |
}) | |
# Results container | |
html_parts.append(""" | |
<div style="background: #0f172a; padding: 0; border-radius: 0 0 16px 16px; box-shadow: 0 4px 20px rgba(0,0,0,0.3); overflow: hidden;"> | |
""") | |
# Individual sentence results | |
for result in sentence_results: | |
if 'error' in result: | |
html_parts.append(f""" | |
<div style="padding: 20px; border-bottom: 1px solid #1e293b;"> | |
<div style="color: #f87171; font-weight: 600; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 18px;">❌</span> | |
เกิดข้อผิดพลาดในการวิเคราะห์ประโยคที่ {result['index']} | |
</div> | |
<p style="color: #94a3b8; margin: 8px 0 0 0; font-size: 14px;">{result['error']}</p> | |
</div> | |
""") | |
else: | |
label_info = result['label_info'] | |
confidence_bar = create_confidence_bar(result['score']) | |
html_parts.append(f""" | |
<div style="padding: 20px; border-bottom: 1px solid #1e293b; transition: all 0.2s ease;" onmouseover="this.style.background='#1e293b'" onmouseout="this.style.background='#0f172a'"> | |
<div style="display: flex; align-items: flex-start; gap: 16px;"> | |
<div style="background: {label_info['bg']}; padding: 12px; border-radius: 50%; min-width: 48px; height: 48px; display: flex; align-items: center; justify-content: center;"> | |
<span style="font-size: 20px;">{label_info['emoji']}</span> | |
</div> | |
<div style="flex: 1;"> | |
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;"> | |
<span style="background: {label_info['color']}; color: #f8fafc; padding: 4px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; text-transform: uppercase;"> | |
{label_info['description']} | |
</span> | |
<span style="color: #94a3b8; font-size: 14px;">ประโยคที่ {result['index']}</span> | |
</div> | |
<p style="color: #f8fafc; margin: 0 0 12px 0; font-size: 16px; line-height: 1.5;"> | |
"{result['sentence'][:150]}{'...' if len(result['sentence']) > 150 else ''}" | |
</p> | |
<div style="color: #94a3b8; font-size: 14px; margin-bottom: 8px;">ความมั่นใจ:</div> | |
{confidence_bar} | |
</div> | |
</div> | |
</div> | |
""") | |
# Summary section | |
total_sentences = len(sentences) | |
avg_confidence = total_confidence / total_sentences if total_sentences > 0 else 0 | |
# Create chart data for summary | |
chart_items = [] | |
colors = {"positive": "#34d399", "negative": "#f87171", "neutral": "#facc15", "question": "#60a5fa", "other": "#64748b"} | |
emojis = {"positive": "😊", "negative": "😢", "neutral": "😐", "question": "🤔", "other": "🔍"} | |
for sentiment, count in sentiment_counts.items(): | |
if count > 0: | |
percentage = (count / total_sentences) * 100 | |
chart_items.append(f""" | |
<div style="display: flex; align-items: center; gap: 12px; padding: 12px; background: rgba(59, 130, 246, 0.1); border-radius: 8px;"> | |
<span style="font-size: 24px;">{emojis.get(sentiment, '🔍')}</span> | |
<div style="flex: 1;"> | |
<div style="font-weight: 600; color: #f8fafc; text-transform: capitalize;">{sentiment}</div> | |
<div style="color: #94a3b8; font-size: 14px;">{count} ประโยค ({percentage:.1f}%)</div> | |
</div> | |
<div style="width: 60px; height: 6px; background: #334155; border-radius: 3px; overflow: hidden;"> | |
<div style="width: {percentage}%; height: 100%; background: {colors.get(sentiment, '#64748b')}; transition: all 0.3s ease;"></div> | |
</div> | |
</div> | |
""") | |
html_parts.append(f""" | |
<div style="padding: 24px; background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);"> | |
<h3 style="color: #f8fafc; margin: 0 0 20px 0; font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 24px;">📊</span> | |
สรุปผลการวิเคราะห์ | |
</h3> | |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 20px;"> | |
<div style="background: #1e293b; padding: 20px; border-radius: 12px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.3);"> | |
<div style="font-size: 32px; font-weight: 700; color: #60a5fa; margin-bottom: 4px;">{total_sentences}</div> | |
<div style="color: #94a3b8; font-size: 14px;">ประโยคทั้งหมด</div> | |
</div> | |
<div style="background: #1e293b; padding: 20px; border-radius: 12px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.3);"> | |
<div style="font-size: 32px; font-weight: 700; color: #34d399; margin-bottom: 4px;">{avg_confidence*100:.0f}%</div> | |
<div style="color: #94a3b8; font-size: 14px;">ความมั่นใจเฉลี่ย</div> | |
</div> | |
</div> | |
<div style="display: grid; gap: 8px;"> | |
{"".join(chart_items)} | |
</div> | |
</div> | |
""") | |
html_parts.append("</div>") | |
return "".join(html_parts) | |
# Modern CSS with dark blue theme | |
CUSTOM_CSS = """ | |
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap'); | |
* { font-family: 'Inter', 'Noto Sans Thai', sans-serif !important; } | |
body, .gradio-container { | |
background: linear-gradient(135deg, #181f2a 0%, #232e3c 100%) !important; | |
min-height: 100vh; | |
} | |
.main-uxui-card { | |
background: #232e3c !important; | |
border-radius: 20px; | |
box-shadow: 0 6px 32px rgba(0,0,0,0.22); | |
border: 1.5px solid #2d3a4d; | |
padding: 32px 28px 28px 28px; | |
margin: 0 0 32px 0; | |
color: #e3e8ef !important; | |
transition: box-shadow 0.2s; | |
} | |
.main-uxui-card:hover { | |
box-shadow: 0 12px 36px rgba(0,0,0,0.28); | |
} | |
.main-uxui-header { | |
text-align: center; | |
margin-bottom: 32px; | |
} | |
.main-uxui-header h1 { | |
font-size: 2.8em; | |
color: #e3e8ef; | |
font-weight: 800; | |
margin-bottom: 0.2em; | |
letter-spacing: 0.5px; | |
} | |
.main-uxui-header p { | |
color: #7da2e3; | |
font-size: 1.25em; | |
margin-top: 0; | |
margin-bottom: 0.5em; | |
} | |
.main-uxui-section-title { | |
font-size: 1.18em; | |
color: #7da2e3; | |
font-weight: 700; | |
margin-bottom: 12px; | |
letter-spacing: 0.2px; | |
display: flex; | |
align-items: center; | |
gap: 8px; | |
} | |
.main-uxui-btn { | |
font-size: 1.13em; | |
padding: 0.9em 2.7em; | |
border-radius: 13px; | |
font-weight: 600; | |
background: linear-gradient(90deg, #2563eb 0%, #1e293b 100%); | |
color: #f8fafc !important; | |
border: none; | |
box-shadow: 0 2px 8px #1e253355; | |
transition: all 0.2s; | |
} | |
.main-uxui-btn:hover { | |
filter: brightness(1.08); | |
box-shadow: 0 6px 18px #1e253377; | |
transform: translateY(-2px) scale(1.03); | |
} | |
.main-uxui-btn.secondary { | |
background: #232e3c; | |
color: #7da2e3 !important; | |
border: 1.5px solid #2d3a4d; | |
} | |
.main-uxui-input, .main-uxui-dropdown { | |
font-size: 1.13em; | |
border-radius: 10px; | |
border: 1.5px solid #2d3a4d; | |
background: #1e2533; | |
color: #e3e8ef; | |
padding: 14px; | |
margin-bottom: 10px; | |
} | |
.main-uxui-dropdown { min-width: 220px; } | |
.main-uxui-output { | |
background: #1e2533; | |
border-radius: 14px; | |
border: 1.5px solid #2d3a4d; | |
color: #e3e8ef; | |
padding: 22px 18px; | |
font-size: 1.08em; | |
min-height: 180px; | |
margin-bottom: 0; | |
} | |
.main-uxui-legend { | |
background: #232e3c; | |
border-radius: 16px; | |
border: 1.5px solid #2d3a4d; | |
color: #7da2e3; | |
padding: 24px 18px; | |
margin-top: 32px; | |
font-size: 1.05em; | |
} | |
.main-uxui-legend .legend-row { | |
display: flex; | |
gap: 24px; | |
flex-wrap: wrap; | |
margin-top: 12px; | |
} | |
.main-uxui-legend .legend-item { | |
flex: 1 1 180px; | |
background: #1e2533; | |
border-radius: 10px; | |
padding: 16px 10px; | |
margin-bottom: 10px; | |
text-align: center; | |
border: 1px solid #2d3a4d; | |
} | |
.main-uxui-legend .legend-item strong { | |
color: #e3e8ef; | |
font-size: 1.08em; | |
} | |
.main-uxui-legend .legend-item small { | |
color: #7da2e3; | |
} | |
@media (max-width: 900px) { | |
.main-uxui-card { padding: 16px 6px; } | |
.main-uxui-header h1 { font-size: 2em; } | |
.main-uxui-section-title { font-size: 1em; } | |
} | |
""" | |
# Create the modern Gradio interface | |
with gr.Blocks(css=CUSTOM_CSS, title="🧠 AI Thai Sentiment Analyzer - วิเคราะห์ความรู้สึกภาษาไทย") as demo: | |
gr.HTML(""" | |
<div class='main-uxui-header'> | |
<h1>🧠 Thai Sentiment Analyzer</h1> | |
<p>AI วิเคราะห์ความรู้สึกภาษาไทยและหลายภาษา <br>ใช้งานง่าย รองรับหลายโมเดล</p> | |
</div> | |
""") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.HTML(""" | |
<div class='main-uxui-card'> | |
<div class='main-uxui-section-title'> | |
<span>🤖</span> เลือกโมเดล AI | |
</div> | |
""") | |
model_dropdown = gr.Dropdown( | |
choices=[choice[1] for choice in MODEL_LIST], | |
value="🏆 MultiSent E5 Pro - แนะนำ (ความแม่นยำสูงสุด)", | |
label="", | |
show_label=False, | |
elem_classes=["main-uxui-dropdown"] | |
) | |
gr.HTML(""" | |
<div class='main-uxui-section-title' style='margin-top:28px;'> | |
<span>💡</span> วิธีใช้งาน | |
</div> | |
<ul style='color:#7da2e3; font-size:1em; line-height:1.7; margin-bottom:0; padding-left:18px;'> | |
<li>พิมพ์ข้อความภาษาไทยหรือภาษาอื่นที่ต้องการวิเคราะห์</li> | |
<li>แยกประโยคด้วยจุด (.) หรือขึ้นบรรทัดใหม่</li> | |
<li>รองรับการวิเคราะห์หลายประโยคพร้อมกัน</li> | |
<li>ผลลัพธ์จะแสดงความมั่นใจและสรุปภาพรวม</li> | |
</ul> | |
</div> | |
""") | |
with gr.Column(scale=2): | |
gr.HTML(""" | |
<div class='main-uxui-card'> | |
<div class='main-uxui-section-title'> | |
<span>✍️</span> ข้อความที่ต้องการวิเคราะห์ | |
</div> | |
""") | |
text_input = gr.Textbox( | |
lines=7, | |
placeholder="ตัวอย่าง: วันนี้อากาศดีมาก ฉันรู้สึกมีความสุขมาก สีฟ้าสวยจริงๆ\nแต่การจราจรติดมาก น่าเบื่อจริงๆ\nโดยรวมแล้วก็โอเคนะ", | |
label="", | |
show_label=False, | |
elem_classes=["main-uxui-input"] | |
) | |
with gr.Row(): | |
analyze_btn = gr.Button("🔍 วิเคราะห์ข้อความ", elem_classes=["main-uxui-btn"]) | |
clear_btn = gr.Button("🗑️ ล้างข้อความ", elem_classes=["main-uxui-btn", "secondary"]) | |
output_box = gr.HTML(""" | |
<div class='main-uxui-output'> | |
<div style='text-align:center; color:#7da2e3; font-size:1.2em;'> | |
<div style='font-size:2.5em; margin-bottom:10px;'>🤖</div> | |
พร้อมวิเคราะห์ความรู้สึก<br>ใส่ข้อความแล้วกดปุ่ม "วิเคราะห์ข้อความ" | |
</div> | |
</div> | |
""") | |
gr.HTML(""" | |
<div class='main-uxui-card' style='margin-top:0;'> | |
<div class='main-uxui-section-title'><span>✨</span> ตัวอย่างข้อความ</div> | |
</div> | |
""") | |
examples = gr.Examples( | |
examples=[ | |
["วันนี้อากาศดีมาก ฉันรู้สึกมีความสุขมาก สีฟ้าสวยจริงๆ"], | |
["ฉันไม่ชอบอาหารนี้เลย รสชาติแปลกมาก เค็มเกินไป"], | |
["วันนี้เป็นยังไงบ้าง?\nเรียนหนังสือกันไหม?\nมีงานอะไรให้ช่วยไหม?"], | |
["บริการดีมาก พนักงานใจดีและเป็นกันเอง\nแต่ของมีราคาแพงไปหน่อย\nโดยรวมแล้วพอใจครับ แนะนำให้เพื่อนมาลอง"], | |
["เมื่อไหร่จะได้เจอกันอีก คิดถึงมากเลย\nแต่ตอนนี้ต้องทำงานหนักก่อน เพื่ออนาคตที่ดี"] | |
], | |
inputs=[text_input], | |
label="", | |
examples_per_page=5 | |
) | |
gr.HTML(""" | |
<div class='main-uxui-legend'> | |
<div class='main-uxui-section-title'><span>🎯</span> คำอธิบายผลการวิเคราะห์</div> | |
<div class='legend-row'> | |
<div class='legend-item'> | |
<div style='font-size:28px;'>😊</div> | |
<strong>Positive</strong><br><small>ความรู้สึกเชิงบวก<br>ดี, สุข, ชอบ</small> | |
</div> | |
<div class='legend-item'> | |
<div style='font-size:28px;'>😢</div> | |
<strong>Negative</strong><br><small>ความรู้สึกเชิงลบ<br>เศร้า, โกรธ, ไม่ชอบ</small> | |
</div> | |
<div class='legend-item'> | |
<div style='font-size:28px;'>😐</div> | |
<strong>Neutral</strong><br><small>ความรู้สึกเป็นกลาง<br>ปกติ, พอใช้ได้</small> | |
</div> | |
<div class='legend-item'> | |
<div style='font-size:28px;'>🤔</div> | |
<strong>Question</strong><br><small>ประโยคคำถาม<br>อะไร, ไหน, เมื่อไหร่</small> | |
</div> | |
</div> | |
</div> | |
""") | |
with gr.Row(equal_height=False): | |
# Left Column - Controls | |
with gr.Column(scale=1): | |
# Model Selection Card | |
with gr.Group(): | |
gr.HTML(""" | |
<div style="background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); color: #f8fafc; padding: 20px; border-radius: 16px 16px 0 0; margin: -20px -20px 20px -20px;"> | |
<h3 style="margin: 0; font-size: 18px; font-weight: 700; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 20px;">🤖</span> | |
เลือกโมเดล AI | |
</h3> | |
<p style="margin: 8px 0 0 0; opacity: 0.9; font-size: 14px;">เลือกโมเดลที่ต้องการใช้ในการวิเคราะห์</p> | |
</div> | |
""") | |
model_dropdown = gr.Dropdown( | |
choices=[choice[1] for choice in MODEL_LIST], | |
value="🏆 MultiSent E5 Pro - แนะนำ (ความแม่นยำสูงสุด)", | |
label="", | |
show_label=False, | |
container=False | |
) | |
# Tips Card | |
with gr.Group(): | |
gr.HTML(""" | |
<div style="background: linear-gradient(135deg, #1e40af 0%, #1e293b 100%); padding: 20px; border-radius: 16px;"> | |
<h4 style="color: #f8fafc; margin: 0 0 16px 0; font-size: 16px; font-weight: 700; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 18px;">💡</span> | |
เคล็ดลับการใช้งาน | |
</h4> | |
<div style="color: #cbd5e1; font-size: 14px; line-height: 1.6;"> | |
<div style="margin-bottom: 12px; display: flex; align-items: flex-start; gap: 8px;"> | |
<span style="color: #60a5fa; font-weight: 600;">•</span> | |
<span>พิมพ์ข้อความภาษาไทยที่ต้องการวิเคราะห์</span> | |
</div> | |
<div style="margin-bottom: 12px; display: flex; align-items: flex-start; gap: 8px;"> | |
<span style="color: #60a5fa; font-weight: 600;">•</span> | |
<span>แยกประโยคด้วยจุด (.) หรือขึ้นบรรทัดใหม่</span> | |
</div> | |
<div style="margin-bottom: 12px; display: flex; align-items: flex-start; gap: 8px;"> | |
<span style="color: #60a5fa; font-weight: 600;">•</span> | |
<span>สามารถวิเคราะห์หลายประโยคพร้อมกันได้</span> | |
</div> | |
<div style="display: flex; align-items: flex-start; gap: 8px;"> | |
<span style="color: #60a5fa; font-weight: 600;">•</span> | |
<span>ผลลัพธ์จะแสดงความมั่นใจและสรุปภาพรวม</span> | |
</div> | |
</div> | |
</div> | |
""") | |
# Right Column - Main Interface | |
with gr.Column(scale=2): | |
# Input Section | |
with gr.Group(): | |
gr.HTML(""" | |
<div style="background: linear-gradient(135deg, #1e40af 0%, #1e293b 100%); padding: 20px; border-radius: 16px 16px 0 0; margin: -20px -20px 20px -20px;"> | |
<h3 style="color: #f8fafc; margin: 0; font-size: 18px; font-weight: 700; display: flex; align-items: center; gap: 8px;"> | |
<span style="font-size: 20px;">✍️</span> | |
ข้อความที่ต้องการวิเคราะห์ | |
</h3> | |
</div> | |
""") | |
text_input = gr.Textbox( | |
lines=6, | |
placeholder="💭 ลองพิมพ์ข้อความที่ต้องการวิเคราะห์...\n\nตัวอย่าง:\nวันนี้อากาศดีมาก ฉันรู้สึกมีความสุข ☀️\nแต่การจราจรติดมาก น่าเบื่อจริงๆ 😤\nโดยรวมแล้วก็โอเคนะ 😊", | |
label="", | |
show_label=False, | |
container=False | |
) | |
with gr.Row(): | |
analyze_btn = gr.Button( | |
"🔍 วิเคราะห์ข้อความ", | |
variant="primary", | |
size="lg", | |
scale=2 | |
) | |
clear_btn = gr.Button( | |
"🗑️ ล้าง", | |
variant="secondary", | |
scale=1 | |
) | |
# Output Section | |
with gr.Row(): | |
with gr.Column(): | |
output_box = gr.HTML( | |
label="📊 ผลการวิเคราะห์", | |
value=""" | |
<div style="padding: 60px 20px; text-align: center; color: #94a3b8; background: rgba(30, 41, 59, 0.9); border-radius: 16px; border: 2px dashed #334155;"> | |
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div> | |
<h3 style="color: #f8fafc; margin: 0 0 8px 0;">พร้อมวิเคราะห์ความรู้สึก</h3> | |
<p style="margin: 0; font-size: 14px;">ใส่ข้อความด้านบนแล้วกดปุ่ม "วิเคราะห์ข้อความ"</p> | |
</div> | |
""" | |
) | |
# Examples Section | |
gr.HTML(""" | |
<div style="margin: 40px 0 20px 0;"> | |
<h3 style="color: #f8fafc; text-align: center; font-size: 20px; font-weight: 700; margin-bottom: 20px; text-shadow: 0 2px 4px rgba(0,0,0,0.4);"> | |
✨ ตัวอย่างการใช้งาน | |
</h3> | |
</div> | |
""") | |
examples = gr.Examples( | |
examples=[ | |
["วันนี้อากาศดีมาก ฉันรู้สึกมีความสุขมาก ☀️ สีฟ้าสวยจริงๆ น่ามองจัง"], | |
["ฉันไม่ชอบอาหารนี้เลย 😤 รสชาติแปลกมาก เค็มเกินไป ไม่อร่อยเลย"], | |
["วันนี้เป็นยังไงบ้าง? 🤔\nเรียนหนังสือกันไหม? 📚\nมีงานอะไรให้ช่วยไหม? 💪"], | |
["บริการดีมาก 👍 พนักงานใจดีและเป็นกันเอง\nแต่ของมีราคาแพงไปหน่อย 💸\nโดยรวมแล้วพอใจครับ แนะนำให้เพื่อนมาลอง ⭐"], | |
["เมื่อไหร่จะได้เจอกันอีก 😢 คิดถึงมากเลย\nแต่ตอนนี้ต้องทำงานหนักก่อน 💪 เพื่ออนาคตที่ดี ✨"] | |
], | |
inputs=[text_input], | |
label="", | |
examples_per_page=5 | |
) | |
# Legend Section | |
gr.HTML(""" | |
<div style="margin: 40px 0 20px 0; background: rgba(30, 58, 138, 0.9); backdrop-filter: blur(10px); border-radius: 20px; padding: 30px; border: 1px solid rgba(59, 130, 246, 0.3);"> | |
<h3 style="color: #f8fafc; text-align: center; font-size: 22px; font-weight: 700; margin-bottom: 25px; text-shadow: 0 2px 4px rgba(0,0,0,0.4);"> | |
🎯 คำอธิบายผลการวิเคราะห์ | |
</h3> | |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px;"> | |
<div style="background: rgba(52, 211, 153, 0.2); backdrop-filter: blur(10px); border-radius: 16px; padding: 20px; text-align: center; border: 1px solid rgba(52, 211, 153, 0.3); transition: all 0.3s ease;" onmouseover="this.style.transform='translateY(-5px)'; this.style.boxShadow='0 10px 25px rgba(52, 211, 153, 0.3)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'"> | |
<div style="font-size: 36px; margin-bottom: 12px;">😊</div> | |
<h4 style="color: #34d399; margin: 0 0 8px 0; font-size: 16px; font-weight: 700;">POSITIVE</h4> | |
<p style="color: #cbd5e1; margin: 0; font-size: 13px; line-height: 1.4;">ความรู้สึกเชิงบวก<br>ดี, สุข, ชอบ, ยินดี</p> | |
</div> | |
<div style="background: rgba(248, 113, 113, 0.2); backdrop-filter: blur(10px); border-radius: 16px; padding: 20px; text-align: center; border: 1px solid rgba(248, 113, 113, 0.3); transition: all 0.3s ease;" onmouseover="this.style.transform='translateY(-5px)'; this.style.boxShadow='0 10px 25px rgba(248, 113, 113, 0.3)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'"> | |
<div style="font-size: 36px; margin-bottom: 12px;">😢</div> | |
<h4 style="color: #f87171; margin: 0 0 8px 0; font-size: 16px; font-weight: 700;">NEGATIVE</h4> | |
<p style="color: #cbd5e1; margin: 0; font-size: 13px; line-height: 1.4;">ความรู้สึกเชิงลบ<br>เศร้า, โกรธ, ไม่ชอบ</p> | |
</div> | |
<div style="background: rgba(250, 204, 21, 0.2); backdrop-filter: blur(10px); border-radius: 16px; padding: 20px; text-align: center; border: 1px solid rgba(250, 204, 21, 0.3); transition: all 0.3s ease;" onmouseover="this.style.transform='translateY(-5px)'; this.style.boxShadow='0 10px 25px rgba(250, 204, 21, 0.3)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'"> | |
<div style="font-size: 36px; margin-bottom: 12px;">😐</div> | |
<h4 style="color: #facc15; margin: 0 0 8px 0; font-size: 16px; font-weight: 700;">NEUTRAL</h4> | |
<p style="color: #cbd5e1; margin: 0; font-size: 13px; line-height: 1.4;">ความรู้สึกเป็นกลาง<br>ปกติ, พอใช้ได้, ธรรมดา</p> | |
</div> | |
<div style="background: rgba(96, 165, 250, 0.2); backdrop-filter: blur(10px); border-radius: 16px; padding: 20px; text-align: center; border: 1px solid rgba(96, 165, 250, 0.3); transition: all 0.3s ease;" onmouseover="this.style.transform='translateY(-5px)'; this.style.boxShadow='0 10px 25px rgba(96, 165, 250, 0.3)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'"> | |
<div style="font-size: 36px; margin-bottom: 12px;">🤔</div> | |
<h4 style="color: #60a5fa; margin: 0 0 8px 0; font-size: 16px; font-weight: 700;">QUESTION</h4> | |
<p style="color: #cbd5e1; margin: 0; font-size: 13px; line-height: 1.4;">ประโยคคำถาม<br>อะไร, ไหน, เมื่อไหร่</p> | |
</div> | |
</div> | |
</div> | |
""") | |
# Footer | |
gr.HTML(""" | |
<div style="text-align: center; padding: 30px 0 10px 0;"> | |
<p style="color: #cbd5e1; font-size: 14px; margin: 0; text-shadow: 0 1px 2px rgba(0,0,0,0.4);"> | |
พัฒนาด้วย ❤️ โดยใช้ Transformers และ Gradio | รองรับโมเดล AI หลากหลาย | |
</p> | |
</div> | |
""") | |
# Event handlers with enhanced functionality | |
def analyze_wrapper(text, model_display_name): | |
if not text.strip(): | |
return """ | |
<div style="padding: 60px 20px; text-align: center; color: #94a3b8; background: rgba(30, 41, 59, 0.9); border-radius: 16px; border: 2px dashed #334155;"> | |
<div style="font-size: 48px; margin-bottom: 16px;">⚠️</div> | |
<h3 style="color: #f87171; margin: 0 0 8px 0;">กรุณาใส่ข้อความ</h3> | |
<p style="margin: 0; font-size: 14px;">ใส่ข้อความที่ต้องการวิเคราะห์ในช่องด้านบน</p> | |
</div> | |
""" | |
# Find actual model name from display name | |
model_name = None | |
for model_tuple in MODEL_LIST: | |
if model_tuple[1] == model_display_name: | |
model_name = model_tuple[0] | |
break | |
if not model_name: | |
model_name = "ZombitX64/MultiSent-E5-Pro" # fallback | |
return analyze_text(text, model_name) | |
def clear_text(): | |
return "", """ | |
<div style="padding: 60px 20px; text-align: center; color: #94a3b8; background: rgba(30, 41, 59, 0.9); border-radius: 16px; border: 2px dashed #334155;"> | |
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div> | |
<h3 style="color: #f8fafc; margin: 0 0 8px 0;">พร้อมวิเคราะห์ความรู้สึก</h3> | |
<p style="margin: 0; font-size: 14px;">ใส่ข้อความด้านบนแล้วกดปุ่ม "วิเคราะห์ข้อความ"</p> | |
</div> | |
""" | |
def auto_analyze(text, model_display_name): | |
if text.strip(): | |
return analyze_wrapper(text, model_display_name) | |
return """ | |
<div style="padding: 60px 20px; text-align: center; color: #94a3b8; background: rgba(30, 41, 59, 0.9); border-radius: 16px; border: 2px dashed #334155;"> | |
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div> | |
<h3 style="color: #f8fafc; margin: 0 0 8px 0;">พร้อมวิเคราะห์ความรู้สึก</h3> | |
<p style="margin: 0; font-size: 14px;">ใส่ข้อความด้านบนแล้วกดปุ่ม "วิเคราะห์ข้อความ"</p> | |
</div> | |
""" | |
# Connect events | |
analyze_btn.click( | |
analyze_wrapper, | |
inputs=[text_input, model_dropdown], | |
outputs=output_box, | |
show_progress=True | |
) | |
text_input.submit( | |
analyze_wrapper, | |
inputs=[text_input, model_dropdown], | |
outputs=output_box, | |
show_progress=True | |
) | |
model_dropdown.change( | |
auto_analyze, | |
inputs=[text_input, model_dropdown], | |
outputs=output_box | |
) | |
clear_btn.click( | |
clear_text, | |
outputs=[text_input, output_box] | |
) | |
# Launch configuration | |
if __name__ == "__main__": | |
demo.queue( | |
max_size=50, | |
default_concurrency_limit=10 | |
).launch( | |
server_name="0.0.0.0", | |
server_port=7860, | |
share=True, | |
show_error=True, | |
show_api=False, | |
quiet=False, | |
favicon_path=None, | |
ssl_verify=False, | |
app_kwargs={ | |
"docs_url": None, | |
"redoc_url": None, | |
} | |
) |