import gradio as gr import time import pandas as pd from datetime import datetime import numpy as np # Импортируем transformers с обработкой ошибок try: from transformers import pipeline transformers_available = True except ImportError: transformers_available = False print("Transformers not available, using mock mode") # История запросов history = [] MAX_HISTORY = 10 # Темы для классификации PREDEFINED_TOPICS = [ "спорт", "политика", "наука", "технологии", "здоровье", "образование", "культура", "экономика", "путешествия", "развлечения", "погода", "происшествия" ] TOPIC_DESCRIPTIONS = { "спорт": "🏀 Спорт", "политика": "🏛️ Политика", "наука": "🔬 Наука", "технологии": "💻 Технологии", "здоровье": "🏥 Здоровье", "образование": "📚 Образование", "культура": "🎭 Культура", "экономика": "💰 Экономика", "путешествия": "✈️ Путешествия", "развлечения": "🎬 Развлечения", "погода": "☀️ Погода", "происшествия": "🚨 Происшествия" } def simple_classifier(text, topics): """Простой классификатор на основе ключевых слов""" text_lower = text.lower() scores = [] # Ключевые слова для каждой темы keywords = { "спорт": ["матч", "игра", "команда", "победил", "счёт", "футбол", "хоккей", "соревнование"], "политика": ["президент", "правительство", "закон", "выборы", "парламент", "министр", "депутат"], "наука": ["учёный", "исследование", "открытие", "лаборатория", "эксперимент", "научный"], "технологии": ["компьютер", "смартфон", "интернет", "программа", "гаджет", "робот", "искусственный интеллект"], "здоровье": ["врач", "больница", "лечение", "болезнь", "пациент", "медицина", "здоровый"], "образование": ["школа", "университет", "студент", "учитель", "экзамен", "урок", "образование"], "культура": ["фильм", "музыка", "театр", "выставка", "художник", "писатель", "книга"], "экономика": ["деньги", "банк", "компания", "рынок", "цена", "экономика", "финансы"], "путешествия": ["отпуск", "отель", "пляж", "горы", "путешествие", "турист", "страна"], "развлечения": ["кино", "сериал", "игра", "концерт", "развлечение", "отдых"], "погода": ["температура", "дождь", "снег", "солнце", "погода", "климат", "ветер"], "происшествия": ["авария", "пожар", "происшествие", "инцидент", "катастрофа", "чрезвычайная ситуация"] } for topic in topics: score = 0 for keyword in keywords.get(topic, []): if keyword in text_lower: score += 1 scores.append(score / max(len(keywords.get(topic, [])), 1)) return scores def classify_topic(text, show_top_n=3): """Классифицирует текст по темам""" # Проверка ошибок if not text or text.strip() == "": return "⚠️ Пожалуйста, введите текст для анализа", "", [] if len(text) > 2000: return "⚠️ Текст слишком длинный (максимум 2000 символов)", "", [] try: # Измеряем время выполнения start_time = time.time() # Пытаемся использовать трансформеры, если доступны if transformers_available: try: classifier = pipeline("zero-shot-classification", model="MoritzLaurer/mDeBERTa-v3-base-mnli-xnli", device=-1) results = classifier( text, candidate_labels=PREDEFINED_TOPICS, multi_label=False ) labels = results['labels'] scores = results['scores'] except Exception as model_error: # Если не получилось с трансформерами, используем простой классификатор print(f"Model error: {model_error}, using simple classifier") scores = simple_classifier(text, PREDEFINED_TOPICS) labels = PREDEFINED_TOPICS else: # Если трансформеры не установлены scores = simple_classifier(text, PREDEFINED_TOPICS) labels = PREDEFINED_TOPICS elapsed_time = time.time() - start_time # Сортируем результаты if isinstance(scores, list): sorted_indices = np.argsort(scores)[::-1][:show_top_n] else: # Если scores уже numpy array sorted_indices = scores.argsort()[::-1][:show_top_n] # Форматируем результаты output_text = f"📊 **Тематическая классификация:**\n\n" for i, idx in enumerate(sorted_indices, 1): topic = labels[idx] score = scores[idx] * 100 description = TOPIC_DESCRIPTIONS.get(topic, topic) # Прогресс-бар bar_length = 20 filled = int(score * bar_length / 100) progress_bar = "█" * filled + "░" * (bar_length - filled) output_text += f"{i}. **{description}** - {score:.1f}%\n" output_text += f" {progress_bar}\n\n" output_text += f"\n⏱️ **Время обработки:** {elapsed_time:.2f} секунд" # Сохраняем в историю timestamp = datetime.now().strftime("%H:%M:%S") top_topic = labels[sorted_indices[0]] history.insert(0, { 'time': timestamp, 'text': text[:50] + ("..." if len(text) > 50 else ""), 'topic': TOPIC_DESCRIPTIONS.get(top_topic, top_topic), 'confidence': f"{scores[sorted_indices[0]]*100:.1f}%" }) # Ограничиваем историю if len(history) > MAX_HISTORY: history.pop() # Создаём DataFrame для таблицы df = pd.DataFrame(history) return output_text, f"✅ Текст успешно обработан за {elapsed_time:.2f} сек", df except Exception as e: return f"❌ **Ошибка:** {str(e)}", "", [] def clear_history(): """Очищает историю запросов""" global history history = [] return pd.DataFrame() # Создаём интерфейс with gr.Blocks(title="Тематический классификатор текста", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🏷️ Тематический классификатор текста") gr.Markdown("Определяет основную тему текста: спорт, политика, наука, технологии и другие") with gr.Row(): with gr.Column(scale=2): # Входные элементы text_input = gr.Textbox( label="📝 Введите текст для анализа", placeholder="Например: 'Сегодня на матче сборная России победила со счётом 3:1...'", lines=5, max_lines=10 ) with gr.Row(): top_n_slider = gr.Slider( minimum=1, maximum=5, value=3, step=1, label="🔢 Количество топ-тем для показа" ) analyze_btn = gr.Button("🚀 Определить тему", variant="primary", size="lg") clear_btn = gr.Button("🧹 Очистить историю", variant="secondary") # Примеры для ТЕМАТИЧЕСКОЙ классификации gr.Markdown("### 📌 Готовые примеры") examples = gr.Examples( examples=[ ["Сегодня на стадионе «Лужники» прошёл финальный матч чемпионата России по футболу. Команда «Спартак» одержала победу со счётом 2:1 над ЦСКА."], ["Парламент принял новый закон о цифровой экономике, который регулирует использование криптовалют и блокчейн-технологий."], ["Учёные из МГУ открыли новый метод лечения рака с помощью наночастиц. Клинические испытания показали эффективность в 85% случаев."], ["Компания Apple представила новый iPhone с революционной камерой и процессором собственной разработки. Продажи начнутся с следующей недели."], ["Врачи рекомендуют увеличить потребление овощей и фруктов для профилактики сердечно-сосудистых заболеваний. Исследования подтвердили снижение риска на 30%."], ["Министерство образования анонсировало реформу ЕГЭ. Изменения коснутся формата экзаменов по математике и русскому языку."], ["В Эрмитаже открылась выставка французских импрессионистов. В экспозиции представлены работы Моне, Ренуара и Дега."] ], inputs=text_input, label="Кликните на любой пример" ) with gr.Column(scale=3): # Результаты output_md = gr.Markdown(label="📊 Результаты классификации") status_text = gr.Textbox(label="✅ Статус", interactive=False) gr.Markdown("### 📋 История запросов") history_table = gr.Dataframe( headers=["Время", "Текст", "Тема", "Уверенность"], datatype=["str", "str", "str", "str"], interactive=False, ) # Обработчики событий analyze_btn.click( fn=classify_topic, inputs=[text_input, top_n_slider], outputs=[output_md, status_text, history_table] ) clear_btn.click( fn=clear_history, inputs=[], outputs=[history_table] ) # Информационный блок gr.Markdown("---") with gr.Accordion("📚 Подробная информация о модели", open=False): gr.Markdown(""" **Используемая модель:** `MoritzLaurer/mDeBERTa-v3-base-mnli-xnli` **Почему эта модель:** - **Лёгкая** (300 МБ вместо 1.6 ГБ) - **Мультиязычная** с хорошей поддержкой русского - **Быстро загружается** на бесплатном CPU **Определяемые темы:** - 🏀 **Спорт** - спортивные события, соревнования, команды - 🏛️ **Политика** - политические новости, выборы, законы - 🔬 **Наука** - научные открытия, исследования - 💻 **Технологии** - IT, гаджеты, программы - 🏥 **Здоровье** - медицина, лечение, здоровье - 📚 **Образование** - обучение, экзамены, школы - 🎭 **Культура** - искусство, музыка, кино - 💰 **Экономика** - финансы, бизнес, рынки - ✈️ **Путешествия** - туризм, страны - 🎬 **Развлечения** - фильмы, игры, шоу - ☀️ **Погода** - климат, температура - 🚨 **Происшествия** - аварии, криминал **Технические детали:** - Модель на основе DeBERTa-v3 - Поддерживает 12 предопределённых тем - Работает на CPU за 1-3 секунды - Поддерживает тексты до 2000 символов """) gr.Markdown("---") gr.Markdown(""" ### ⚠️ Ограничения и примечания 1. Максимальная длина текста: **2000 символов** 2. Поддерживает русский и английский языки 3. Может определять только одну основную тему 4. Для сложных текстов может потребоваться ручная проверка 5. Точность: ~70-80% на новостных текстах """) if __name__ == "__main__": demo.launch(debug=False)