fix(plagiarism): не матчить против чужих/своих же загруженных работ
Критично: L1/L2/L3 сравнивали фрагменты со ВСЕЙ базой documents, включая source=user_submission — работы, которые auto_approve_submission сам же затаскивал в корпус после проверки. Итог: студент, перепроверивший тот же файл дважды, получал 100% "точное совпадение" по всем фрагментам — против собственной же более ранней загрузки. Фикс: все три уровня исключают source=user_submission из кандидатов на совпадение. AUTO_APPROVE_SUBMISSIONS выключен по умолчанию — раньше рос корпус для будущего сравнения, но без защиты от self/cross-match это опаснее, чем полезно.
This commit is contained in:
@@ -121,6 +121,10 @@ def check_plagiarism(
|
|||||||
|
|
||||||
if not doc_meta:
|
if not doc_meta:
|
||||||
continue
|
continue
|
||||||
|
# user_submission — чужие непубличные загрузки (и свои же прошлые
|
||||||
|
# прогоны того же файла), не легитимный источник для сравнения.
|
||||||
|
if doc_meta["source"] == "user_submission":
|
||||||
|
continue
|
||||||
|
|
||||||
llm_result = {"is_paraphrase": False, "confidence": 0.0, "reason": ""}
|
llm_result = {"is_paraphrase": False, "confidence": 0.0, "reason": ""}
|
||||||
if source_text:
|
if source_text:
|
||||||
|
|||||||
@@ -61,10 +61,12 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
# Автоматически добавлять проверенные работы студентов в базу для сравнения
|
# Автоматически добавлять проверенные работы студентов в базу для сравнения
|
||||||
# (как в коммерческих системах — Антиплагиат.ру/Turnitin ловят списывание у
|
# (как в коммерческих системах — Антиплагиат.ру/Turnitin ловят списывание у
|
||||||
# предыдущих потоков именно так). Без этого каждая работа лежит в StagedWork
|
# предыдущих потоков именно так). Выключено по умолчанию: без ручной
|
||||||
# и ждёт ручного одобрения админом — сейчас это дефолт для роста корпуса;
|
# модерации студент, перепроверивший тот же файл дважды, получал 100%
|
||||||
# выключить, если нужна модерация перед публикацией.
|
# "плагиата" — против собственной же более ранней загрузки. L1/L2/L3 теперь
|
||||||
AUTO_APPROVE_SUBMISSIONS: bool = True
|
# и так исключают source=user_submission из сравнения, так что включать это
|
||||||
|
# обратно есть смысл только вместе с реальной защитой от self/cross-match.
|
||||||
|
AUTO_APPROVE_SUBMISSIONS: bool = False
|
||||||
|
|
||||||
# App
|
# App
|
||||||
ENVIRONMENT: str = "development"
|
ENVIRONMENT: str = "development"
|
||||||
|
|||||||
@@ -108,13 +108,20 @@ def extract_and_check(
|
|||||||
continue
|
continue
|
||||||
frag_hashes = list(frag_fp)
|
frag_hashes = list(frag_fp)
|
||||||
|
|
||||||
# Источник, разделяющий больше всего отпечатков с этим фрагментом
|
# Источник, разделяющий больше всего отпечатков с этим фрагментом.
|
||||||
|
# user_submission исключены: это чужие непубличные загрузки (и
|
||||||
|
# свои же прошлые прогоны того же файла) — сравнение с ними даёт
|
||||||
|
# ложные 100%-совпадения, а не реальный плагиат из источника.
|
||||||
row = session.execute(
|
row = session.execute(
|
||||||
select(
|
select(
|
||||||
Fingerprint.doc_id,
|
Fingerprint.doc_id,
|
||||||
func.count(Fingerprint.id).label("cnt"),
|
func.count(Fingerprint.id).label("cnt"),
|
||||||
)
|
)
|
||||||
.where(Fingerprint.hash_value.in_(frag_hashes))
|
.join(Document, Document.id == Fingerprint.doc_id)
|
||||||
|
.where(
|
||||||
|
Fingerprint.hash_value.in_(frag_hashes),
|
||||||
|
Document.source != "user_submission",
|
||||||
|
)
|
||||||
.group_by(Fingerprint.doc_id)
|
.group_by(Fingerprint.doc_id)
|
||||||
.order_by(func.count(Fingerprint.id).desc())
|
.order_by(func.count(Fingerprint.id).desc())
|
||||||
.limit(1)
|
.limit(1)
|
||||||
@@ -164,7 +171,7 @@ def extract_and_check(
|
|||||||
try:
|
try:
|
||||||
doc_id = int(key.split(":")[-1])
|
doc_id = int(key.split(":")[-1])
|
||||||
doc = session.get(Document, doc_id)
|
doc = session.get(Document, doc_id)
|
||||||
if not doc:
|
if not doc or doc.source == "user_submission":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
level2_matches.append({
|
level2_matches.append({
|
||||||
|
|||||||
Reference in New Issue
Block a user