| import streamlit as st |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline |
| import torch |
|
|
| device = "cuda" if torch.cuda.is_available() else "cpu" |
| |
|
|
| @st.cache_resource |
| def load_model(): |
| model_path = "HoiAlice/bert-paper-classifier-arxiv" |
| inference_tokenizer = AutoTokenizer.from_pretrained(model_path) |
| inference_model = AutoModelForSequenceClassification.from_pretrained(model_path) |
| return pipeline("text-classification", model=inference_model, tokenizer=inference_tokenizer, top_k=None) |
|
|
| def top_pct(preds, threshold: float = 0.9): |
| """Возвращает топ предсказаний, пока их суммарная вероятность не превысит threshold""" |
| if not preds: |
| return [] |
| preds = sorted(preds, key=lambda x: -x["score"]) |
| cum_score = 0 |
| for i, item in enumerate(preds): |
| cum_score += item["score"] |
| if cum_score >= threshold: |
| break |
| return preds[:(i+1)] |
|
|
| def format_predictions(preds) -> str: |
| """Форматирует предсказания для вывода""" |
| if not preds: |
| return "Нет результатов" |
| return "\n".join([f"{i+1}. {item['label']} (score {item['score']:.2f})" for i, item in enumerate(preds)]) |
|
|
| |
| st.set_page_config(page_title="Классификатор научных статей", page_icon="📚") |
| st.title("📚 Классификатор научных статей по тематикам") |
| st.write("Введите текст абстракта статьи, и модель определит наиболее подходящие тематики:") |
|
|
| |
| abstract = st.text_area( |
| "Текст абстракта:", |
| height=200, |
| placeholder="Введите текст научного абстракта здесь..." |
| ) |
|
|
| |
| threshold = st.slider( |
| "Порог уверенности (суммарная вероятность тематик):", |
| min_value=0.5, |
| max_value=1.0, |
| value=0.9, |
| step=0.05 |
| ) |
|
|
| if st.button("Определить тематики"): |
| if not abstract.strip(): |
| st.warning("Пожалуйста, введите текст абстракта") |
| else: |
| with st.spinner("Загружаем модель... (это может занять некоторое время при первом запуске)"): |
| classifier = load_model() |
| |
| if classifier is not None: |
| with st.spinner("Анализируем текст..."): |
| try: |
| |
| predictions = classifier(abstract)[0] |
| |
| top_predictions = top_pct(predictions, threshold) |
| |
| |
| st.subheader("Результаты классификации:") |
| st.text(format_predictions(top_predictions)) |
| |
| |
| st.subheader("Визуализация:") |
| chart_data = {p['label']: p['score'] for p in top_predictions} |
| st.bar_chart(chart_data) |
| |
| except Exception as e: |
| st.error(f"Произошла ошибка при анализе текста: {str(e)}") |
|
|
| |
| with st.sidebar: |
| st.markdown(""" |
| ## О сервисе |
| Этот сервис использует модель уже обученную языковую модель для выделения тематики статьи по ее описанию. |
| |
| ### Как использовать: |
| 1. Введите текст абстракта в поле ввода |
| 2. Отрегулируйте порог уверенности (по умолчанию 0.90) |
| 3. Нажмите кнопку "Определить тематики" |
| |
| ### Техническая информация: |
| - Используемый датасет: [arXiv papers](https://www.kaggle.com/datasets/neelshah18/arxivdataset) |
| - Модель: [BiomedNLP-PubMedBERT](https://huggingface.co/microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract) |
| |
| ### Благодарности: |
| - Большое спасибо Диму Сафину, Ekaterina Zabairachnaya и Андрею Панферову за содержательную критику и активную поддержку, |
| без вас бы я уже ливнул бы отседова. |
| """ |
| ) |