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