OlenaBondaruk's picture
Update app.py
ae81bad verified
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
from transformers import pipeline
import gradio as gr
import pandas as pd
from datetime import datetime
# --- 1. ПІДГОТОВКА МОДЕЛЕЙ ---
print("Завантаження моделей... зачекайте")
# Модель для аналізу тональності
sentiment_pipe = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
# Модель для резюмування
model_name = "sshleifer/distilbart-cnn-12-6"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
print("Моделі готові до роботи!")
# --- 2. ЛОГІКА ТА ВІЗУАЛІЗАЦІЯ ---
def format_sentiment_result(label, score):
"""Генерація HTML-картки з анімацією та логікою впевненості (Завдання 1)"""
if score > 0.9:
confidence_text = "💎 Дуже впевнено"
elif score >= 0.7:
confidence_text = "✅ Впевнено"
else:
confidence_text = "🤔 Непевно"
primary_color = "#6366f1" if label == "POSITIVE" else "#f43f5e"
bg_gradient = "linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%)" if label == "POSITIVE" else "linear-gradient(135deg, #fff1f2 0%, #ffe4e6 100%)"
bar_width = int(score * 100)
return f"""
<style>
@keyframes slideIn {{ from {{ width: 0%; }} to {{ width: {bar_width}%; }} }}
.custom-card {{
padding: 20px; border-radius: 20px; background: {bg_gradient};
border: 3px solid {primary_color}; box-shadow: 8px 8px 15px rgba(0,0,0,0.05);
font-family: 'Segoe UI', sans-serif; transition: all 0.3s;
}}
.prog-container {{ background: #fff; border-radius: 10px; height: 12px; margin: 15px 0; overflow: hidden; border: 1px solid #ddd; }}
.prog-bar {{ background: {primary_color}; height: 100%; width: {bar_width}%; animation: slideIn 1.5s ease-out; }}
.status-badge {{ background: {primary_color}; color: white; padding: 4px 12px; border-radius: 50px; font-weight: bold; font-size: 0.85em; }}
</style>
<div class="custom-card">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span style="font-size: 1.5em; font-weight: 800; color: {primary_color};">{label}</span>
<span class="status-badge">{confidence_text}</span>
</div>
<div class="prog-container"><div class="prog-bar"></div></div>
<div style="color: #555; font-size: 0.95em;">Точність: <b>{score:.1%}</b></div>
</div>
"""
def get_stats(history):
"""Обчислення розширеної статистики сесії (Завдання 2)"""
if not history:
return "📊 **Статистика:** Очікування перших даних для аналізу..."
total = len(history)
pos_count = sum(1 for h in history if h["Результат"] == "POSITIVE")
avg_conf = sum(h["raw_score"] for h in history) / total
max_words = max(h["word_count"] for h in history)
return (
f"🔍 **Аналітика сесії**\n\n"
f"📝 Всього текстів: **{total}** | 😊 Позитивних: **{pos_count}** | 😢 Негативних: **{total - pos_count}**\n\n"
f"📈 Сер. впевненість: **{avg_conf:.1%}** | 📏 Найдовший текст: **{max_words} слів**\n\n"
f"🕒 Перший аналіз: **{history[0]['Час']}** | Останній: **{history[-1]['Час']}**"
)
def analyze_process(text, history):
"""Основна функція обробки Sentiment Analysis"""
text = text.strip()
if not text:
return "<p style='color:gray;'>Будь ласка, введіть текст для аналізу</p>", history, pd.DataFrame(history) if history else pd.DataFrame(), get_stats(history)
res = sentiment_pipe(text)[0]
label, score = res["label"], res["score"]
entry = {
"Час": datetime.now().strftime("%H:%M:%S"),
"Текст": text[:45] + "..." if len(text) > 45 else text,
"Результат": label,
"Впевн.": f"{score:.1%}",
"raw_score": score,
"word_count": len(text.split())
}
updated_history = history + [entry]
df = pd.DataFrame(updated_history)[["Час", "Текст", "Результат", "Впевн."]]
return format_sentiment_result(label, score), updated_history, df, get_stats(updated_history)
def summarize_process(text, max_len):
"""Функція резюмування тексту"""
if not text.strip(): return "Введіть довгий текст для скорочення..."
inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=1024)
outputs = model.generate(**inputs, max_length=max_len, min_length=20, do_sample=False)
return tokenizer.decode(outputs[0], skip_special_tokens=True)
def push_to_wishlist(history, current_wishlist):
"""Додавання останнього аналізу до Wishlist State (Завдання 3)"""
if not history:
return current_wishlist, "⚠ Немає результатів для збереження!"
last = history[-1]
new_item = f"⭐ [{last['Результат']}] {last['Текст']} (Точність: {last['Впевн.']})"
updated_wishlist = current_wishlist + [new_item]
return updated_wishlist, "\n".join(updated_wishlist)
# --- 3. ІНТЕРФЕЙС GRADIO (Завдання 4) ---
with gr.Blocks(title="NLP Analytics Pro", theme=gr.themes.Glass()) as demo:
# Заголовки
gr.HTML("<h1 style='text-align: center; color: #6366f1; margin-bottom: 0;'>🚀 NLP Analytics Dashboard</h1>")
gr.HTML("<p style='text-align: center; color: gray;'>Інтелектуальний аналіз тональності та резюмування</p>")
# Реєстрація States
history_state = gr.State([])
wishlist_state = gr.State([])
with gr.Row():
# Секція 1: Аналіз Тональності
with gr.Column(scale=1):
gr.Markdown("### 💬 Sentiment Analysis")
txt_input = gr.Textbox(label="Ваш текст для аналізу", placeholder="Наприклад: I love this project...", lines=3)
with gr.Row():
btn_run = gr.Button("Аналізувати ▶", variant="primary")
btn_save = gr.Button("Зберегти в Обране ⭐", variant="secondary")
out_html = gr.HTML("<div style='border: 2px dashed #ccc; border-radius: 20px; height: 120px; display: flex; align-items: center; justify-content: center; color: gray;'>Результат з'явиться тут</div>")
# Секція 2: Резюмування
with gr.Column(scale=1):
gr.Markdown("### 📝 Summarization")
sum_input = gr.Textbox(label="Довгий текст (English)", lines=3, placeholder="Вставте статтю для резюмування...")
sum_slider = gr.Slider(30, 250, value=80, label="Максимальна довжина резюме")
btn_sum = gr.Button("Створити резюме", variant="primary")
sum_output = gr.Textbox(label="Стислий зміст", interactive=False, lines=4)
gr.HTML("<hr style='opacity: 0.2; margin: 20px 0;'>")
with gr.Row():
# Блок статистики (Завдання 2)
with gr.Column(scale=1):
stats_md = gr.Markdown(get_stats([]))
# Блок Wishlist (Завдання 3)
with gr.Column(scale=1):
gr.Markdown("### 📌 Ваше обране (Wishlist)")
wish_out = gr.Textbox(label=None, placeholder="Збережені результати з'являться тут...", interactive=False, lines=6)
# Акордеон з історією
with gr.Accordion("📋 Повна історія сесії", open=False):
history_table = gr.DataFrame(headers=["Час", "Текст", "Результат", "Впевн."], datatype=["str", "str", "str", "str"])
btn_clear = gr.Button("🗑 Очистити все (History + Wishlist)", variant="stop")
# ОБРОБКА ПОДІЙ
btn_run.click(
fn=analyze_process,
inputs=[txt_input, history_state],
outputs=[out_html, history_state, history_table, stats_md]
)
btn_sum.click(
fn=summarize_process,
inputs=[sum_input, sum_slider],
outputs=sum_output
)
btn_save.click(
fn=push_to_wishlist,
inputs=[history_state, wishlist_state],
outputs=[wishlist_state, wish_out]
)
# Синхронне очищення (Завдання 3)
btn_clear.click(
fn=lambda: ([], pd.DataFrame(), get_stats([]), [], ""),
inputs=None,
outputs=[history_state, history_table, stats_md, wishlist_state, wish_out]
)
demo.launch(favicon_path="myphoto.png")