nlp / app.py
SherifAnar's picture
Update app.py
3251b33 verified
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 для работы в ограниченной среде
@st.cache_resource
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()