Продолжение seed_ru_sources.py: все 30 базовых RU-тем + 26 EN-тем (OpenAlex) + 4 категории arXiv уже отработаны (done). Этот скрипт добавляет НОВОЕ поверх — углубление RU (специализированные подотрасли права/экономики/IT, 29 тем) и расширение EN на области, которых не было (право, лингвистика, история, искусство, науки о Земле и т.д., 20 тем) + 15 новых тем arXiv. Идемпотентно (префиксы ru2:/oa3:/arxiv2: не пересекаются с уже существующими). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
135 lines
6.7 KiB
Python
135 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
||
"""Расширение корпуса вширь — новые дисциплины, которых ещё нет в parse_sources.
|
||
|
||
Продолжение scripts/seed_ru_sources.py: та заливка покрыла 30 базовых русских
|
||
дисциплин + был уже собран seed-корпус из ~26 английских тем (OpenAlex) и 4
|
||
категорий arXiv. Этот скрипт добавляет НОВЫЕ темы поверх уже сделанного —
|
||
углубление RU (специализированные подотрасли права/экономики/IT) и расширение EN
|
||
(область права/лингвистики/искусства/наук о Земле и т.д., которых ещё не было),
|
||
плюс новые категории arXiv.
|
||
|
||
Идемпотентно (по name, с префиксами ru2:/oa3:/arxiv2: — не пересекаются с уже
|
||
существующими ru:/corpus:/oa2:/arxiv:). Dry-run по умолчанию.
|
||
|
||
Запуск:
|
||
python scripts/seed_broad_corpus.py # план
|
||
python scripts/seed_broad_corpus.py --apply # записать в БД
|
||
"""
|
||
|
||
import argparse
|
||
import os
|
||
from pathlib import Path
|
||
|
||
# (name_suffix, source_type, query, lang, limit)
|
||
RU_DEEP = [ # углубление: специализированные RU-темы, которых не было в первой волне
|
||
"семейное право", "административное право", "уголовный процесс",
|
||
"гражданский процесс", "международное право", "предпринимательское право",
|
||
"налоговое право", "земельное право", "экологическое право",
|
||
"информационная безопасность", "искусственный интеллект", "нейронные сети",
|
||
"веб-разработка", "архитектура зданий", "дизайн", "музыкальное искусство",
|
||
"физическая культура", "спортивная медицина", "туризм", "логистика",
|
||
"инновационный менеджмент", "антикризисное управление", "аудит",
|
||
"страхование", "банковское дело", "инвестиции",
|
||
"внешнеэкономическая деятельность", "региональная экономика", "демография",
|
||
]
|
||
|
||
EN_OPENALEX_NEW = [ # области, которых не было в первой EN-волне
|
||
"law", "political science", "linguistics", "literature studies", "history",
|
||
"philosophy", "anthropology", "geography", "agriculture",
|
||
"business management", "finance", "architecture", "astronomy", "geology",
|
||
"pharmacology", "nursing", "veterinary science", "art history",
|
||
"music theory", "religious studies",
|
||
]
|
||
|
||
EN_ARXIV_NEW = [ # темы поиска arXiv, не пересекаются с уже сделанными 4
|
||
"natural language processing", "reinforcement learning", "quantum physics",
|
||
"particle physics", "condensed matter physics", "number theory",
|
||
"statistics methodology", "signal processing", "distributed systems",
|
||
"software engineering", "bioinformatics", "econometrics", "optimization",
|
||
"graph theory", "information theory",
|
||
]
|
||
|
||
|
||
def _load_env() -> None:
|
||
env = Path(__file__).resolve().parent.parent / ".env"
|
||
if not env.exists():
|
||
return
|
||
for line in env.read_text(encoding="utf-8").splitlines():
|
||
line = line.strip()
|
||
if not line or line.startswith("#") or "=" not in line:
|
||
continue
|
||
key, _, val = line.partition("=")
|
||
os.environ.setdefault(key.strip(), val.strip())
|
||
|
||
|
||
def _pg_dsn() -> dict:
|
||
return {
|
||
"host": os.environ.get("POSTGRES_HOST", "localhost"),
|
||
"port": int(os.environ.get("POSTGRES_PORT", "5432")),
|
||
"dbname": os.environ.get("POSTGRES_DB", "antiplagiator"),
|
||
"user": os.environ.get("POSTGRES_USER", "antiplagiator"),
|
||
"password": os.environ.get("POSTGRES_PASSWORD", ""),
|
||
}
|
||
|
||
|
||
def _build_rows(ru_limit: int, en_limit: int, arxiv_limit: int) -> list[tuple]:
|
||
rows = []
|
||
rows += [(f"ru2:{t}", "cyberleninka", t, "ru", ru_limit) for t in RU_DEEP]
|
||
rows += [(f"oa3:{t}", "openalex", t, None, en_limit) for t in EN_OPENALEX_NEW]
|
||
rows += [(f"arxiv2:{t}", "arxiv", t, None, arxiv_limit) for t in EN_ARXIV_NEW]
|
||
return rows
|
||
|
||
|
||
def main() -> None:
|
||
ap = argparse.ArgumentParser(description=__doc__,
|
||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||
ap.add_argument("--apply", action="store_true", help="реально записать в БД (иначе dry-run)")
|
||
ap.add_argument("--ru-limit", type=int, default=500)
|
||
ap.add_argument("--en-limit", type=int, default=1000)
|
||
ap.add_argument("--arxiv-limit", type=int, default=800)
|
||
args = ap.parse_args()
|
||
|
||
_load_env()
|
||
rows = _build_rows(args.ru_limit, args.en_limit, args.arxiv_limit)
|
||
total_potential = sum(r[4] for r in rows)
|
||
|
||
print(f"Новых источников: {len(rows)} "
|
||
f"(RU углубление {len(RU_DEEP)}, EN OpenAlex {len(EN_OPENALEX_NEW)}, "
|
||
f"arXiv {len(EN_ARXIV_NEW)})")
|
||
print(f"Потенциальный объём (верхняя граница): ~{total_potential} документов")
|
||
|
||
if not args.apply:
|
||
print("\n[dry-run] запустите с --apply, чтобы записать в parse_sources.")
|
||
for name, stype, q, _lang, lim in rows[:10]:
|
||
print(f" {name:32} [{stype:12}] limit={lim} → {q!r}")
|
||
print(f" ... и ещё {len(rows) - 10}")
|
||
return
|
||
|
||
import psycopg2
|
||
|
||
conn = psycopg2.connect(**_pg_dsn())
|
||
conn.autocommit = True
|
||
created, skipped, ids = 0, 0, []
|
||
with conn.cursor() as cur:
|
||
for name, stype, query, lang, limit in rows:
|
||
cur.execute("SELECT id FROM parse_sources WHERE name = %s", (name,))
|
||
if cur.fetchone():
|
||
skipped += 1
|
||
continue
|
||
cur.execute(
|
||
'INSERT INTO parse_sources '
|
||
'(source_type, name, query, lang, "limit", enabled, last_status, docs_added) '
|
||
"VALUES (%s, %s, %s, %s, %s, TRUE, 'idle', 0) RETURNING id",
|
||
(stype, name, query, lang, limit),
|
||
)
|
||
ids.append(cur.fetchone()[0])
|
||
created += 1
|
||
conn.close()
|
||
|
||
print(f"\nСоздано: {created}, пропущено (уже были): {skipped}")
|
||
print(f"ID новых источников: {ids}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|