yogl commited on
Commit
8b29500
·
verified ·
1 Parent(s): 34bda3e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -53
app.py CHANGED
@@ -82,12 +82,13 @@ except Exception:
82
 
83
 
84
  # ==========================
85
- # CSS (шрифт таблицы 80%)
86
  # ==========================
87
 
88
  st.markdown(
89
  """
90
  <style>
 
91
  div[data-testid="stDataFrame"] { font-size: 80% !important; }
92
  div[data-testid="stDataFrame"] * { font-size: 80% !important; }
93
 
@@ -122,6 +123,11 @@ def _safe_text(x: Any) -> str:
122
  return s
123
 
124
 
 
 
 
 
 
125
  def _norm_openalex_url(x: Any) -> str:
126
  s = _safe_text(x)
127
  if not s:
@@ -146,12 +152,6 @@ def _keyify(label: str) -> str:
146
  return "k_" + "".join(ch if ch.isalnum() else "_" for ch in label).strip("_")
147
 
148
 
149
- def _as_float_series(s: Any) -> pd.Series:
150
- """Гарантирует float64 + NaN (никаких None / object)."""
151
- out = pd.to_numeric(s, errors="coerce")
152
- return out.astype("float64")
153
-
154
-
155
  # ==========================
156
  # ФИЛЬТРЫ (UI)
157
  # ==========================
@@ -258,7 +258,7 @@ def load_oa_enrichment() -> pd.DataFrame:
258
 
259
  for c in ["h_index", "i10_index", "works_count", "cited_by_count"]:
260
  if c in df.columns:
261
- df[c] = pd.to_numeric(df[c], errors="coerce").astype("float64")
262
 
263
  keep = ["reg_norm", "openalex_url", "orcid_url", "h_index", "i10_index", "works_count", "cited_by_count"]
264
  keep = [c for c in keep if c in df.columns]
@@ -428,13 +428,18 @@ def build_result_df(results):
428
 
429
  protection_year = extract_year_int(meta.get("protection_date", None))
430
 
 
 
 
 
 
431
  rows.append(
432
  {
433
  "№": r["rank"],
434
  "score": float(round(score, 4)),
435
  "fio": meta.get("fio", None),
436
  "title": meta.get("title", None),
437
- "author_org_short": meta.get("author_org_short", None),
438
  "dissertation_type": meta.get("dissertation_type", None),
439
  "protection_year": protection_year,
440
  "registration_number": meta.get("registration_number", reg),
@@ -472,10 +477,10 @@ def run_search(
472
  df_raw["openalex_url"] = _get("openalex_url", "").map(_norm_openalex_url)
473
  df_raw["orcid_url"] = _get("orcid_url", "").map(_norm_orcid_url)
474
 
475
- df_raw["h_index"] = _as_float_series(_get("h_index", np.nan))
476
- df_raw["i10_index"] = _as_float_series(_get("i10_index", np.nan))
477
- df_raw["works_count"] = _as_float_series(_get("works_count", np.nan))
478
- df_raw["cited_by_count"] = _as_float_series(_get("cited_by_count", np.nan))
479
  else:
480
  df_raw["openalex_url"] = ""
481
  df_raw["orcid_url"] = ""
@@ -484,36 +489,31 @@ def run_search(
484
  df_raw["works_count"] = np.nan
485
  df_raw["cited_by_count"] = np.nan
486
 
487
- # UI: ФИО — текст; ORCID — отдельная безымянная ссылка (пусто если нет)
488
  fio_txt = df_raw["fio"].map(_safe_text)
489
- orcid_link = df_raw["orcid_url"].map(_safe_text)
 
490
 
491
  title_txt = df_raw["title"].map(_safe_text)
492
  vak_link = df_raw["vak_link"].map(_safe_text)
 
493
 
494
  df_ui = pd.DataFrame(
495
  {
496
  "_rid": np.arange(len(df_raw)),
497
- "Сходство": _as_float_series(df_raw["score"]),
498
- " ": orcid_link, # безымянная колонка-ссылка (ORCID)
499
- "ФИО": fio_txt, # всегда текст (не ссылка)
500
- " ": vak_link, # ещё одна безымянная колонка-ссылка (ВАК)
501
- "Название диссертации": title_txt, # всегда текст (не ссылка)
502
  "Организация": df_raw["author_org_short"].map(_safe_text),
503
- "Год": _as_float_series(df_raw["protection_year"]),
504
  "OpenAlex": df_raw["openalex_url"].map(_safe_text),
505
- "h-index": _as_float_series(df_raw["h_index"]),
506
- "i10-index": _as_float_series(df_raw["i10_index"]),
507
- "Работ": _as_float_series(df_raw["works_count"]),
508
- "Цитат": _as_float_series(df_raw["cited_by_count"]),
509
  }
510
  ).set_index("_rid", drop=True)
511
 
512
- # гарантированно убрать "None" в текстовых колонках (если вдруг прилетело строкой)
513
- for c in df_ui.select_dtypes(include=["object"]).columns:
514
- df_ui[c] = df_ui[c].map(_safe_text)
515
-
516
- # Excel
517
  df_excel_ru = df_raw.rename(columns=COLUMN_LABELS_RU_EXCEL)
518
  output = io.BytesIO()
519
  with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
@@ -639,9 +639,7 @@ if isinstance(df_ui_saved, pd.DataFrame) and not df_ui_saved.empty:
639
  selection_mode="multi-row",
640
  column_order=[
641
  "Сходство",
642
- " ",
643
  "ФИО",
644
- " ",
645
  "Название диссертации",
646
  "Организация",
647
  "Год",
@@ -653,34 +651,26 @@ if isinstance(df_ui_saved, pd.DataFrame) and not df_ui_saved.empty:
653
  ],
654
  column_config={
655
  "Сходство": st.column_config.NumberColumn("Сходство", format="%.4f", width="small"),
656
-
657
- # ORCID: ссылка только если URL не пустой
658
- " ": st.column_config.LinkColumn("",
659
- display_text="ORCID",
660
- width="small",
661
- help="Профиль ORCID (если найден)."),
662
-
663
- "ФИО": st.column_config.TextColumn("ФИО", width="medium"),
664
-
665
- # ВАК: ссылка только если URL не пустой
666
- " ": st.column_config.LinkColumn("",
667
- display_text="ВАК",
668
- width="small",
669
- help="Открыть запись на сайте ВАК (если есть ссылка)."),
670
-
671
- "Название диссертации": st.column_config.TextColumn("Название диссертации", width="large"),
672
  "Организация": st.column_config.TextColumn("Организация", width="large"),
673
-
674
  "Год": st.column_config.NumberColumn("Год", format="%.0f", width="small"),
675
-
676
  "OpenAlex": st.column_config.LinkColumn(
677
  "OpenAlex",
678
  display_text=r"https://openalex\.org/(A\d+)",
679
  width="small",
680
  help="Профиль автора в OpenAlex (если найден).",
681
  ),
682
-
683
- # Форматирование + NaN => пустая ячейка; сортировка numeric
684
  "h-index": st.column_config.NumberColumn("h-index", format="%.0f", width="small"),
685
  "i10-index": st.column_config.NumberColumn("i10-index", format="%.0f", width="small"),
686
  "Работ": st.column_config.NumberColumn("Работ", format="%.0f", width="small"),
@@ -692,7 +682,6 @@ if isinstance(df_ui_saved, pd.DataFrame) and not df_ui_saved.empty:
692
  if sel is not None and sel.rows is not None:
693
  st.session_state.selected_rids = list(sel.rows)
694
 
695
- # Компенсация отсутствия word-wrap: показываем полный текст выбранных строк
696
  if st.session_state.selected_rids:
697
  with st.expander("Полный текст (для выбранных строк)", expanded=False):
698
  for rid in st.session_state.selected_rids[:50]:
 
82
 
83
 
84
  # ==========================
85
+ # CSS: уменьшение шрифта таблицы до ~80%
86
  # ==========================
87
 
88
  st.markdown(
89
  """
90
  <style>
91
+ /* уменьшение шрифта вокруг dataframes */
92
  div[data-testid="stDataFrame"] { font-size: 80% !important; }
93
  div[data-testid="stDataFrame"] * { font-size: 80% !important; }
94
 
 
123
  return s
124
 
125
 
126
+ def _safe_fragment(s: Any) -> str:
127
+ t = _safe_text(s).replace("#", " ").replace("\n", " ").strip()
128
+ return t
129
+
130
+
131
  def _norm_openalex_url(x: Any) -> str:
132
  s = _safe_text(x)
133
  if not s:
 
152
  return "k_" + "".join(ch if ch.isalnum() else "_" for ch in label).strip("_")
153
 
154
 
 
 
 
 
 
 
155
  # ==========================
156
  # ФИЛЬТРЫ (UI)
157
  # ==========================
 
258
 
259
  for c in ["h_index", "i10_index", "works_count", "cited_by_count"]:
260
  if c in df.columns:
261
+ df[c] = pd.to_numeric(df[c], errors="coerce")
262
 
263
  keep = ["reg_norm", "openalex_url", "orcid_url", "h_index", "i10_index", "works_count", "cited_by_count"]
264
  keep = [c for c in keep if c in df.columns]
 
428
 
429
  protection_year = extract_year_int(meta.get("protection_date", None))
430
 
431
+ # ВАЖНО: используем author_org_short (fallback на author_org_name если вдруг короткого нет)
432
+ org_short = meta.get("author_org_short", None)
433
+ if org_short is None or (isinstance(org_short, float) and pd.isna(org_short)) or str(org_short).lower() in {"none", "nan"}:
434
+ org_short = meta.get("author_org_name", None)
435
+
436
  rows.append(
437
  {
438
  "№": r["rank"],
439
  "score": float(round(score, 4)),
440
  "fio": meta.get("fio", None),
441
  "title": meta.get("title", None),
442
+ "author_org_short": org_short,
443
  "dissertation_type": meta.get("dissertation_type", None),
444
  "protection_year": protection_year,
445
  "registration_number": meta.get("registration_number", reg),
 
477
  df_raw["openalex_url"] = _get("openalex_url", "").map(_norm_openalex_url)
478
  df_raw["orcid_url"] = _get("orcid_url", "").map(_norm_orcid_url)
479
 
480
+ df_raw["h_index"] = pd.to_numeric(_get("h_index", np.nan), errors="coerce").astype("float64")
481
+ df_raw["i10_index"] = pd.to_numeric(_get("i10_index", np.nan), errors="coerce").astype("float64")
482
+ df_raw["works_count"] = pd.to_numeric(_get("works_count", np.nan), errors="coerce").astype("float64")
483
+ df_raw["cited_by_count"] = pd.to_numeric(_get("cited_by_count", np.nan), errors="coerce").astype("float64")
484
  else:
485
  df_raw["openalex_url"] = ""
486
  df_raw["orcid_url"] = ""
 
489
  df_raw["works_count"] = np.nan
490
  df_raw["cited_by_count"] = np.nan
491
 
 
492
  fio_txt = df_raw["fio"].map(_safe_text)
493
+ orcid_url = df_raw["orcid_url"].map(_safe_text)
494
+ fio_cell = np.where(orcid_url != "", orcid_url + "#" + fio_txt.map(_safe_fragment), fio_txt)
495
 
496
  title_txt = df_raw["title"].map(_safe_text)
497
  vak_link = df_raw["vak_link"].map(_safe_text)
498
+ title_cell = np.where(vak_link != "", vak_link + "#" + title_txt.map(_safe_fragment), title_txt)
499
 
500
  df_ui = pd.DataFrame(
501
  {
502
  "_rid": np.arange(len(df_raw)),
503
+ "Сходство": pd.to_numeric(df_raw["score"], errors="coerce").astype("float64"),
504
+ "ФИО": fio_cell,
505
+ "Название диссертации": title_cell,
506
+ # ВАЖНО: отображаем author_org_short
 
507
  "Организация": df_raw["author_org_short"].map(_safe_text),
508
+ "Год": pd.to_numeric(df_raw["protection_year"], errors="coerce").astype("float64"),
509
  "OpenAlex": df_raw["openalex_url"].map(_safe_text),
510
+ "h-index": df_raw["h_index"],
511
+ "i10-index": df_raw["i10_index"],
512
+ "Работ": df_raw["works_count"],
513
+ "Цитат": df_raw["cited_by_count"],
514
  }
515
  ).set_index("_rid", drop=True)
516
 
 
 
 
 
 
517
  df_excel_ru = df_raw.rename(columns=COLUMN_LABELS_RU_EXCEL)
518
  output = io.BytesIO()
519
  with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
 
639
  selection_mode="multi-row",
640
  column_order=[
641
  "Сходство",
 
642
  "ФИО",
 
643
  "Название диссертации",
644
  "Организация",
645
  "Год",
 
651
  ],
652
  column_config={
653
  "Сходство": st.column_config.NumberColumn("Сходство", format="%.4f", width="small"),
654
+ "ФИО": st.column_config.LinkColumn(
655
+ "ФИО",
656
+ display_text=r"(?:.*#)?(.*)$",
657
+ width="medium",
658
+ help="Если для автора найден ORCID — ФИО кликабельно и ведёт на ORCID.",
659
+ ),
660
+ "Название диссертации": st.column_config.LinkColumn(
661
+ "Название диссертации",
662
+ display_text=r"(?:.*#)?(.*)$",
663
+ width="large",
664
+ help="Если есть ссылка ВАК — название кликабельно и ведёт на ВАК.",
665
+ ),
 
 
 
 
666
  "Организация": st.column_config.TextColumn("Организация", width="large"),
 
667
  "Год": st.column_config.NumberColumn("Год", format="%.0f", width="small"),
 
668
  "OpenAlex": st.column_config.LinkColumn(
669
  "OpenAlex",
670
  display_text=r"https://openalex\.org/(A\d+)",
671
  width="small",
672
  help="Профиль автора в OpenAlex (если найден).",
673
  ),
 
 
674
  "h-index": st.column_config.NumberColumn("h-index", format="%.0f", width="small"),
675
  "i10-index": st.column_config.NumberColumn("i10-index", format="%.0f", width="small"),
676
  "Работ": st.column_config.NumberColumn("Работ", format="%.0f", width="small"),
 
682
  if sel is not None and sel.rows is not None:
683
  st.session_state.selected_rids = list(sel.rows)
684
 
 
685
  if st.session_state.selected_rids:
686
  with st.expander("Полный текст (для выбранных строк)", expanded=False):
687
  for rid in st.session_state.selected_rids[:50]: