Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -54,20 +54,24 @@ def to_class(pred: float) -> int:
|
|
| 54 |
if pred < THRESHOLDS_5Y[2]: return 2
|
| 55 |
return 3
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
def compute_meta_from_inputs(
|
| 59 |
publication_year: int,
|
| 60 |
abstract: str,
|
| 61 |
title: str,
|
| 62 |
author_count: int,
|
| 63 |
-
s2_fields: list,
|
| 64 |
) -> torch.Tensor:
|
|
|
|
| 65 |
meta = [
|
| 66 |
float(publication_year) / 2026,
|
| 67 |
float(np.log1p(len(abstract))),
|
| 68 |
float(np.log1p(len(title))),
|
| 69 |
float(np.log1p(min(author_count, 200))),
|
| 70 |
-
|
| 71 |
]
|
| 72 |
return torch.tensor([meta], dtype=torch.float)
|
| 73 |
|
|
@@ -147,19 +151,15 @@ def predict(title: str, abstract: str, meta_tensor: torch.Tensor):
|
|
| 147 |
est_citations = float(np.expm1(max(score, 0))) # inverse of log1p
|
| 148 |
return pred_class, score, est_citations
|
| 149 |
|
| 150 |
-
|
| 151 |
st.title("📊 Citation Impact Predictor")
|
| 152 |
st.markdown("""
|
| 153 |
### 🤔 Зачем это нужно?
|
| 154 |
-
|
| 155 |
Узнать заранее по названию абстракту, числу авторов, году выхода и наличию открытого доступа стоит ли вообще тратить время на изучение статьи
|
| 156 |
Мы делим работы на 4 категории:
|
| 157 |
-
|
| 158 |
- 🗑️ **Мусор** — не стоит читать
|
| 159 |
- 📄 **Середняк** — можно читать, если это ваша область и более сильных работ сейчас нет
|
| 160 |
- 📈 **Сильная работа** — стоит обратить внимание
|
| 161 |
- 🏆 **Топ** — читать обязательно
|
| 162 |
-
|
| 163 |
💡 Это не заменяет экспертную оценку —
|
| 164 |
но помогает быстро отфильтровать поток научных работ.
|
| 165 |
""")
|
|
@@ -187,8 +187,6 @@ st.sidebar.header("🔢 Metadata")
|
|
| 187 |
|
| 188 |
pub_year = st.sidebar.number_input("Publication year", 2000, 2024, 2020)
|
| 189 |
author_count = st.sidebar.number_input("Author count", min_value=1, max_value=200, value=3)
|
| 190 |
-
has_s2_fields = st.sidebar.checkbox("Has field-of-study tags?", value=True)
|
| 191 |
-
s2_fields = ["Computer Science"] if has_s2_fields else []
|
| 192 |
|
| 193 |
# ── Main panel: wide left for input, narrow right for button ──────────────────
|
| 194 |
col_left, col_right = st.columns([4, 1])
|
|
@@ -241,12 +239,12 @@ if run:
|
|
| 241 |
if not title and not abstract:
|
| 242 |
st.warning("Please provide at least a title or abstract.")
|
| 243 |
else:
|
|
|
|
| 244 |
meta_tensor = compute_meta_from_inputs(
|
| 245 |
publication_year=int(pub_year),
|
| 246 |
abstract=abstract,
|
| 247 |
title=title,
|
| 248 |
-
author_count=int(author_count)
|
| 249 |
-
s2_fields=s2_fields,
|
| 250 |
)
|
| 251 |
|
| 252 |
with st.spinner("Running inference…"):
|
|
@@ -312,4 +310,4 @@ st.caption(
|
|
| 312 |
"Model: fine-tuned `allenai/specter2_base` · "
|
| 313 |
"Classes defined by log1p(5-year citations) thresholds [1.5, 3.5, 5.5] · "
|
| 314 |
"© 2026 Citation Predictor"
|
| 315 |
-
)
|
|
|
|
| 54 |
if pred < THRESHOLDS_5Y[2]: return 2
|
| 55 |
return 3
|
| 56 |
|
| 57 |
+
def noise_score(text: str) -> float:
|
| 58 |
+
"""Доля букв в тексте — простая метрика осмысленности"""
|
| 59 |
+
letters = sum(c.isalpha() for c in text)
|
| 60 |
+
return letters / max(len(text), 1)
|
| 61 |
|
| 62 |
def compute_meta_from_inputs(
|
| 63 |
publication_year: int,
|
| 64 |
abstract: str,
|
| 65 |
title: str,
|
| 66 |
author_count: int,
|
|
|
|
| 67 |
) -> torch.Tensor:
|
| 68 |
+
text = (title + " " + abstract).strip()
|
| 69 |
meta = [
|
| 70 |
float(publication_year) / 2026,
|
| 71 |
float(np.log1p(len(abstract))),
|
| 72 |
float(np.log1p(len(title))),
|
| 73 |
float(np.log1p(min(author_count, 200))),
|
| 74 |
+
noise_score(text) # осмысленность текста
|
| 75 |
]
|
| 76 |
return torch.tensor([meta], dtype=torch.float)
|
| 77 |
|
|
|
|
| 151 |
est_citations = float(np.expm1(max(score, 0))) # inverse of log1p
|
| 152 |
return pred_class, score, est_citations
|
| 153 |
|
|
|
|
| 154 |
st.title("📊 Citation Impact Predictor")
|
| 155 |
st.markdown("""
|
| 156 |
### 🤔 Зачем это нужно?
|
|
|
|
| 157 |
Узнать заранее по названию абстракту, числу авторов, году выхода и наличию открытого доступа стоит ли вообще тратить время на изучение статьи
|
| 158 |
Мы делим работы на 4 категории:
|
|
|
|
| 159 |
- 🗑️ **Мусор** — не стоит читать
|
| 160 |
- 📄 **Середняк** — можно читать, если это ваша область и более сильных работ сейчас нет
|
| 161 |
- 📈 **Сильная работа** — стоит обратить внимание
|
| 162 |
- 🏆 **Топ** — читать обязательно
|
|
|
|
| 163 |
💡 Это не заменяет экспертную оценку —
|
| 164 |
но помогает быстро отфильтровать поток научных работ.
|
| 165 |
""")
|
|
|
|
| 187 |
|
| 188 |
pub_year = st.sidebar.number_input("Publication year", 2000, 2024, 2020)
|
| 189 |
author_count = st.sidebar.number_input("Author count", min_value=1, max_value=200, value=3)
|
|
|
|
|
|
|
| 190 |
|
| 191 |
# ── Main panel: wide left for input, narrow right for button ──────────────────
|
| 192 |
col_left, col_right = st.columns([4, 1])
|
|
|
|
| 239 |
if not title and not abstract:
|
| 240 |
st.warning("Please provide at least a title or abstract.")
|
| 241 |
else:
|
| 242 |
+
text = (title + " " + abstract).strip()
|
| 243 |
meta_tensor = compute_meta_from_inputs(
|
| 244 |
publication_year=int(pub_year),
|
| 245 |
abstract=abstract,
|
| 246 |
title=title,
|
| 247 |
+
author_count=int(author_count)
|
|
|
|
| 248 |
)
|
| 249 |
|
| 250 |
with st.spinner("Running inference…"):
|
|
|
|
| 310 |
"Model: fine-tuned `allenai/specter2_base` · "
|
| 311 |
"Classes defined by log1p(5-year citations) thresholds [1.5, 3.5, 5.5] · "
|
| 312 |
"© 2026 Citation Predictor"
|
| 313 |
+
)
|