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