Spaces:
Sleeping
Sleeping
| 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()) |