Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| # Конфигурация страницы ДО ЛЮБЫХ ДРУГИХ КОМАНД Streamlit | |
| st.set_page_config( | |
| page_title="Анализ текстовых данных", | |
| page_icon="📊", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # Теперь импортируем остальные библиотеки | |
| import json | |
| import pandas as pd | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| from collections import Counter | |
| import nltk | |
| import os | |
| import warnings | |
| import tempfile | |
| # Игнорируем предупреждения | |
| warnings.filterwarnings("ignore") | |
| # Настройка NLTK для работы в ограниченной среде | |
| def setup_nltk(): | |
| # Создаем временную директорию для NLTK данных | |
| nltk_data_path = os.path.join(tempfile.gettempdir(), 'nltk_data') | |
| os.makedirs(nltk_data_path, exist_ok=True) | |
| # Устанавливаем путь для NLTK данных | |
| nltk.data.path.append(nltk_data_path) | |
| # Скачиваем необходимые данные | |
| try: | |
| nltk.data.find('tokenizers/punkt') | |
| except LookupError: | |
| nltk.download('punkt', download_dir=nltk_data_path, quiet=True) | |
| # Инициализация NLTK | |
| setup_nltk() | |
| from nltk.tokenize import word_tokenize | |
| from razdel import tokenize as razdel_tokenize | |
| from nltk.stem import SnowballStemmer | |
| # Пример данных в памяти | |
| SAMPLE_DATA = [ | |
| {"text": "Привет, как дела? Это пример текста для анализа.", "preprocessed_text": "Привет, как дела? Это пример текста для анализа."}, | |
| {"text": "Natural language processing is fascinating.", "preprocessed_text": "Natural language processing is fascinating."}, | |
| {"text": "Машинное обучение и обработка естественного языка.", "preprocessed_text": "Машинное обучение и обработка естественного языка."}, | |
| {"text": "Hello world! This is a test sentence.", "preprocessed_text": "Hello world! This is a test sentence."}, | |
| {"text": "Токенизация важна для обработки текста.", "preprocessed_text": "Токенизация важна для обработки текста."}, | |
| {"text": "The quick brown fox jumps over the lazy dog.", "preprocessed_text": "The quick brown fox jumps over the lazy dog."}, | |
| {"text": "Нейронные сети используются в современных NLP системах.", "preprocessed_text": "Нейронные сети используются в современных NLP системах."}, | |
| {"text": "Python is a great programming language for data science.", "preprocessed_text": "Python is a great programming language for data science."}, | |
| {"text": "Анализ текста помогает понять его структуру и содержание.", "preprocessed_text": "Анализ текста помогает понять его структуру и содержание."}, | |
| {"text": "Machine learning models require large amounts of data.", "preprocessed_text": "Machine learning models require large amounts of data."} | |
| ] | |
| # Функции токенизации | |
| def nltk_tokenize(text, language): | |
| try: | |
| lang = 'russian' if language == 'Русский' else 'english' | |
| tokens = word_tokenize(text, language=lang) | |
| return [t for t in tokens if t.strip()] | |
| except Exception: | |
| # Fallback на простой split | |
| return [t for t in text.split() if t.strip()] | |
| def razdel_tokenize_func(text, language): | |
| if language == 'Русский': | |
| try: | |
| tokens = [token.text for token in razdel_tokenize(text) if token.text.strip()] | |
| return tokens | |
| except Exception: | |
| return [t for t in text.split() if t.strip()] | |
| return [t for t in text.split() if t.strip()] | |
| def snowball_stem(tokens, language): | |
| try: | |
| lang = 'russian' if language == 'Русский' else 'english' | |
| stemmer = SnowballStemmer(lang) | |
| return [stemmer.stem(token) for token in tokens if token.strip()] | |
| except Exception: | |
| return tokens | |
| def compute_metrics(tokens_list, vocab): | |
| if not tokens_list: | |
| return {'token_lengths': [], 'oov_percentage': 0, 'token_freq': {}, 'vocab_size': 0} | |
| token_lengths = [len(token) for tokens in tokens_list for token in tokens] | |
| total_tokens = len(token_lengths) | |
| oov_tokens = sum(1 for tokens in tokens_list for token in tokens if token not in vocab) | |
| oov_percentage = oov_tokens / total_tokens * 100 if total_tokens > 0 else 0 | |
| token_freq = Counter(token for tokens in tokens_list for token in tokens) | |
| top_tokens = dict(sorted(token_freq.items(), key=lambda x: x[1], reverse=True)[:10]) | |
| return { | |
| 'token_lengths': token_lengths, | |
| 'oov_percentage': oov_percentage, | |
| 'token_freq': top_tokens, | |
| 'vocab_size': len(set(token for tokens in tokens_list for token in tokens)) | |
| } | |
| def read_uploaded_file(uploaded_file): | |
| """Чтение загруженного файла в память""" | |
| texts = [] | |
| try: | |
| content = uploaded_file.getvalue().decode('utf-8') | |
| for line in content.splitlines(): | |
| try: | |
| article = json.loads(line.strip()) | |
| text = article.get('preprocessed_text', article.get('cleaned_text', article.get('text', ''))) | |
| if text and len(text.strip()) > 0: | |
| texts.append(text.strip()) | |
| except: | |
| continue | |
| return texts | |
| except Exception as e: | |
| st.error(f"Ошибка чтения файла: {str(e)}") | |
| return [] | |
| def main(): | |
| st.title("📊 Интерактивная обработка текста") | |
| st.markdown("Анализ текстовых данных с различными методами токенизации") | |
| # Сайдбар с настройками | |
| with st.sidebar: | |
| st.header("⚙️ Настройки") | |
| language = st.selectbox("Выберите язык", ["Русский", "Английский"]) | |
| st.header("📁 Данные") | |
| use_sample = st.checkbox("Использовать пример датасета", value=True) | |
| uploaded_file = st.file_uploader("Или загрузите JSONL", type=["jsonl"]) | |
| st.header("🔧 Методы") | |
| method = st.selectbox("Выберите метод", ['nltk', 'razdel', 'nltk_snowball']) | |
| st.header("ℹ️ О приложении") | |
| st.info(""" | |
| Это приложение анализирует текстовые данные с помощью: | |
| - **NLTK**: Стандартная токенизация | |
| - **Razdel**: Для русского языка | |
| - **Snowball**: Токенизация + стемминг | |
| """) | |
| # Определяем какие данные использовать | |
| texts = [] | |
| if use_sample: | |
| texts = [item['preprocessed_text'] for item in SAMPLE_DATA] | |
| st.success(f"✅ Используется пример датасета ({len(texts)} текстов)") | |
| if uploaded_file is not None: | |
| uploaded_texts = read_uploaded_file(uploaded_file) | |
| if uploaded_texts: | |
| texts = uploaded_texts | |
| st.success(f"✅ Загружен файл: {uploaded_file.name} ({len(texts)} текстов)") | |
| else: | |
| st.error("❌ Не удалось прочитать загруженный файл") | |
| if not use_sample: | |
| return | |
| if not texts: | |
| st.info("👆 Пожалуйста, выберите пример датасета или загрузите свой файл") | |
| return | |
| # Ограничиваем для демо | |
| if len(texts) > 50: | |
| st.info(f"ℹ️ Будут обработаны первые 50 текстов из {len(texts)}") | |
| texts = texts[:50] | |
| # Показываем пример текстов | |
| with st.expander("📝 Просмотреть данные"): | |
| for i, text in enumerate(texts[:5]): | |
| st.write(f"**Текст {i+1}:** {text}") | |
| if len(texts) > 5: | |
| st.write(f"... и еще {len(texts) - 5} текстов") | |
| # Обработка | |
| if st.button("🚀 Запустить обработку", type="primary", use_container_width=True): | |
| with st.spinner("Обработка текстов..."): | |
| tokens_list = [] | |
| vocab = set() | |
| progress_bar = st.progress(0) | |
| status_text = st.empty() | |
| for i, text in enumerate(texts): | |
| status_text.text(f"Обработка текста {i+1}/{len(texts)}") | |
| # Выбор метода | |
| if method == 'nltk': | |
| tokens = nltk_tokenize(text, language) | |
| elif method == 'razdel': | |
| tokens = razdel_tokenize_func(text, language) | |
| elif method == 'nltk_snowball': | |
| base_tokens = nltk_tokenize(text, language) | |
| tokens = snowball_stem(base_tokens, language) | |
| else: | |
| tokens = [t for t in text.split() if t.strip()] | |
| if tokens: | |
| tokens_list.append(tokens) | |
| vocab.update(tokens) | |
| progress_bar.progress((i + 1) / len(texts)) | |
| status_text.text("✅ Обработка завершена!") | |
| if not tokens_list: | |
| st.error("❌ Не удалось получить токены!") | |
| return | |
| # Вычисление метрик | |
| metrics = compute_metrics(tokens_list, vocab) | |
| # Результаты | |
| st.subheader("📈 Результаты анализа") | |
| # Основные метрики | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric("Размер словаря", metrics['vocab_size']) | |
| with col2: | |
| st.metric("Доля OOV", f"{metrics['oov_percentage']:.2f}%") | |
| with col3: | |
| st.metric("Текстов", len(tokens_list)) | |
| with col4: | |
| total_tokens = sum(len(tokens) for tokens in tokens_list) | |
| st.metric("Всего токенов", total_tokens) | |
| # Визуализация | |
| tab1, tab2, tab3 = st.tabs(["📏 Длины токенов", "📊 Частотность", "📋 Топ токены"]) | |
| with tab1: | |
| if metrics['token_lengths']: | |
| fig1 = px.histogram( | |
| metrics['token_lengths'], | |
| nbins=15, | |
| title="Распределение длин токенов", | |
| labels={'value': 'Длина токена', 'count': 'Количество'}, | |
| color_discrete_sequence=['#FF4B4B'] | |
| ) | |
| fig1.update_layout( | |
| showlegend=False, | |
| xaxis_title="Длина токена", | |
| yaxis_title="Количество" | |
| ) | |
| st.plotly_chart(fig1, use_container_width=True) | |
| else: | |
| st.info("Нет данных для визуализации длин токенов") | |
| with tab2: | |
| if metrics['token_freq']: | |
| token_df = pd.DataFrame( | |
| metrics['token_freq'].items(), | |
| columns=['Токен', 'Частота'] | |
| ) | |
| fig2 = px.bar( | |
| token_df, | |
| x='Токен', | |
| y='Частота', | |
| title="Топ-10 самых частых токенов", | |
| color='Частота', | |
| color_continuous_scale='Blues' | |
| ) | |
| fig2.update_layout( | |
| xaxis_title="Токен", | |
| yaxis_title="Частота" | |
| ) | |
| st.plotly_chart(fig2, use_container_width=True) | |
| else: | |
| st.info("Нет данных для визуализации частотности") | |
| with tab3: | |
| if metrics['token_freq']: | |
| token_df = pd.DataFrame( | |
| metrics['token_freq'].items(), | |
| columns=['Токен', 'Частота'] | |
| ) | |
| token_df['Доля (%)'] = (token_df['Частота'] / token_df['Частота'].sum() * 100).round(2) | |
| st.dataframe( | |
| token_df, | |
| use_container_width=True, | |
| hide_index=True | |
| ) | |
| # Скачивание результатов | |
| csv = token_df.to_csv(index=False) | |
| st.download_button( | |
| "💾 Скачать результаты (CSV)", | |
| csv, | |
| file_name="token_analysis.csv", | |
| mime="text/csv", | |
| use_container_width=True | |
| ) | |
| else: | |
| st.info("Нет данных о токенах") | |
| # Запуск приложения | |
| if __name__ == '__main__': | |
| main() |