SentimentFlow / app.py
SandraKorol's picture
Update app.py
c1bbeb1 verified
Raw
History Blame Contribute Delete
8.65 kB
from transformers import pipeline
import gradio as gr
import pandas as pd
from datetime import datetime
sentiment_pipe = pipeline('sentiment-analysis',model='distilbert-base-uncased-finetuned-sst-2-english')
def format_sentiment_result(label, score):
color = '#6366f1' if label == 'POSITIVE' else '#ef4444'
bg = '#eef2ff' if label == 'POSITIVE' else '#fef2f2'
emoji = '😊' if label == 'POSITIVE' else '😞'
bar_w = int(score * 100)
if score > 0.9:
confidence_text = 'Дуже впевнено'
elif score >= 0.7:
confidence_text = 'Впевнено'
else:
confidence_text = 'Непевно'
return f'''
<div style="padding:20px; border-radius:14px; background:{bg};
border:2px solid {color}; font-family:Arial;">
<style>
@keyframes fillBar {{
from {{ width: 0%; }}
to {{ width: {bar_w}%; }}
}}
</style>
<div style="font-size:2.5em; text-align:center">{emoji}</div>
<div style="text-align:center; font-size:1.5em; font-weight:bold;
color:{color}; margin:8px 0">
{label}
</div>
<div style="background:#e5e7eb; border-radius:10px; height:12px; margin:10px 0; overflow:hidden">
<div style="background:{color}; width:{bar_w}%;
height:12px; border-radius:10px;
animation: fillBar 1s ease-out;">
</div>
</div>
<div style="width:100%; margin:0 auto;">
<div style="text-align:center; color:#555">
Впевненість:
<b style="color: {color}">{score:.1%}</b>
</div>
<div style="text-align:center; margin-top:6px; color:#666; font-size:0.95em">
{confidence_text}
</div>
</div>
</div>
'''
def summarize_stream(text):
"""Streaming-генератор для поступового виводу резюме."""
if not text.strip():
yield 'Введіть текст для резюмування'
return
if len(text.split()) < 30:
yield 'Текст занадто короткий (потрібно мінімум 30 слів)'
return
words_in = text.split()
if len(words_in) > 700:
text = ' '.join(words_in[:700])
result = summarizer_pipe(text, max_length=100, min_length=25)[0]
summary = result['summary_text']
words = summary.split()
accumulated = ''
for word in words:
accumulated += word + ' '
yield accumulated.strip()
ratio = len(words_in) / max(len(words), 1)
yield accumulated.strip() + f'\n\n[Стиснення: {ratio:.1f}x | {len(words_in)}{len(words)} слів]'
def clear_all():
return (
[],
[],
'**Статистика сесії:** немає даних',
[],
''
)
def analyze_with_history_and_stats(text, history):
"""
Повертає 4 значення: html_card, history, DataFrame, stats_markdown.
"""
if not text.strip():
empty_html = '<p style="color:#999; text-align:center">Введіть текст</p>'
df = pd.DataFrame(history) if history else pd.DataFrame( columns=['Час', 'Текст', 'Результат', 'Впевн.'])
return empty_html, history, df, get_stats(history)
res = sentiment_pipe(text)[0]
label = res['label']
score = res['score']
html_card = format_sentiment_result(label, score)
entry = {'Час' : datetime.now().strftime('%H:%M:%S'),
'Текст' : text[:45] + '...' if len(text) > 45 else text,
'Результат': label,
'Впевн.' : f'{score:.1%}'
}
updated_history = history + [entry]
df = pd.DataFrame(updated_history)
stats = get_stats(updated_history)
return html_card, updated_history, df, stats
def get_stats(history):
"""Повертає Markdown-рядок зі статистикою сесії."""
if not history:
return '📊 **Статистика сесії:** немає даних'
total = len(history)
pos = sum(1 for h in history if h['Результат'] == 'POSITIVE')
neg = total - pos
pct_p = pos / total * 100
pct_n = neg / total * 100
longest = max(history, key=lambda h: len(h["Текст"].split()))
longest_words = len(longest["Текст"].split())
times = [h["Час"] for h in history]
from datetime import datetime
times = []
for h in history:
t = h.get("Час")
if isinstance(t, datetime):
times.append(t)
first_time = min(times).strftime("%H:%M:%S") if times else "N/A"
last_time = max(times).strftime("%H:%M:%S") if times else "N/A"
return (
f'📊 **Статистика сесії**\n\n'
f'Всього аналізів: **{total}** | '
f'Позитивних: **{pos}** ({pct_p:.0f}%) | '
f'Негативних: **{neg}** ({pct_n:.0f}%)'
f'Найдовший текст: **{longest_words} слів**\n | '
f'Перша сесія: **{first_time}**\n | '
f'Остання сесія: **{last_time}** | '
)
def save_to_wishlist(text, wishlist):
if not text.strip():
return wishlist, '\n'.join(wishlist)
wishlist.append(text)
return wishlist, '\n'.join(
f'{i + 1}. {item}'
for i, item in enumerate(wishlist)
)
with gr.Blocks(title='NLP Analytics Dashboard', theme=gr.themes.Glass(),
) as demo:
gr.Markdown('# NLP Analytics Dashboard')
gr.Markdown('Аналізуй текст, накопичуй статистику, порівнюй результати.')
history_state = gr.State([])
wishlist_state = gr.State([])
with gr.Row(equal_height=False):
with gr.Column(scale=1):
gr.Markdown('### Аналіз тональності')
text_in = gr.Textbox(
lines=5,
label='Текст',
placeholder='Введіть відгук, твіт або будь-який текст...'
)
char_count = gr.Markdown('Символів: 0')
analyze_btn = gr.Button('Аналізувати', variant='primary')
clear_btn = gr.Button('Очистити', variant='secondary')
save_btn = gr.Button('Зберегти', variant='secondary')
html_out = gr.HTML(label='Результат')
with gr.Column(scale=1):
gr.Markdown('### Резюмування')
sum_text = gr.Textbox(
lines=5,
label='Текст для резюмування',
placeholder='Вставте статтю або довгий текст...'
)
with gr.Accordion('Параметри резюмування', open=False):
max_len = gr.Slider(
30, 200, value=80, step=10,
label='Макс. довжина (токени)'
)
sum_btn = gr.Button('Резюмувати ', variant='primary')
sum_out = gr.Textbox(lines=4, label='Резюме', interactive=False)
gr.Markdown('---')
stats_md = gr.Markdown('**Статистика сесії:** немає даних')
with gr.Accordion('Історія аналізів', open=True):
history_table = gr.DataFrame(
headers=['Час', 'Текст', 'Результат', 'Впевн.'],
label='Всі аналізи цієї сесії',
interactive=False
)
with gr.Accordion('Wishlist', open=True):
wishlist_box = gr.Textbox(
label='Збережені тексти',
lines=8,
interactive=False
)
text_in.change(
fn=lambda txt: f'Символів: {len(txt)} | Слів: {len(txt.split())}',
inputs=text_in,
outputs=char_count
)
for trigger in [analyze_btn.click, text_in.submit]:
trigger(
fn=analyze_with_history_and_stats,
inputs=[text_in, history_state],
outputs=[html_out, history_state, history_table, stats_md]
)
save_btn.click(
fn=save_to_wishlist,
inputs=[text_in, wishlist_state],
outputs=[wishlist_state, wishlist_box]
)
clear_btn.click(
fn=clear_all,
outputs=[
history_state,
history_table,
stats_md,
wishlist_state,
wishlist_box
]
)
sum_btn.click(
fn=summarize_stream,
inputs=sum_text,
outputs=sum_out
)
demo.launch(favicon_path='favicon.ico', theme=gr.themes.Glass())