feat(plagiarism): показывать тематически близкие источники, а не только нарушения
Кандидаты уровня 3 (FAISS), которые прошли порог семантической схожести, но LLM не подтвердила заимствование, раньше молча отбрасывались. Теперь это отдельный блок "recommendations" в отчёте — не плагиат, но источники, полезные для раскрытия темы.
This commit is contained in:
@@ -99,6 +99,7 @@ def check_plagiarism(
|
||||
ollama = OllamaClient()
|
||||
vector_store = get_backend()
|
||||
semantic_matches: list[dict] = []
|
||||
related_candidates: list[dict] = []
|
||||
|
||||
for i, fragment in enumerate(fragments):
|
||||
frag_text = fragment.get("text", "")
|
||||
@@ -125,19 +126,29 @@ def check_plagiarism(
|
||||
if source_text:
|
||||
llm_result = ollama.check_paraphrase(source_text, frag_text)
|
||||
|
||||
candidate = {
|
||||
"fragment": frag_text[:300],
|
||||
"position_start": fragment.get("start", 0),
|
||||
"position_end": fragment.get("end", len(frag_text)),
|
||||
"similarity": round(score * 100, 1),
|
||||
"source_title": doc_meta["title"],
|
||||
"source_url": doc_meta["url"],
|
||||
"source_db": doc_meta["source"],
|
||||
}
|
||||
|
||||
if llm_result.get("is_paraphrase") and llm_result.get("confidence", 0.0) >= LLM_CONFIDENCE_THRESHOLD:
|
||||
semantic_matches.append({
|
||||
"fragment": frag_text[:300],
|
||||
"position_start": fragment.get("start", 0),
|
||||
"position_end": fragment.get("end", len(frag_text)),
|
||||
"similarity": round(score * 100, 1),
|
||||
**candidate,
|
||||
"method": "semantic+llm",
|
||||
"confidence": llm_result["confidence"],
|
||||
"reason": llm_result.get("reason", ""),
|
||||
"source_title": doc_meta["title"],
|
||||
"source_url": doc_meta["url"],
|
||||
"source_db": doc_meta["source"],
|
||||
})
|
||||
else:
|
||||
# Похоже по смыслу, но LLM не подтвердила заимствование —
|
||||
# не плагиат, но тематически близкая работа: кандидат в
|
||||
# рекомендации "источники для раскрытия темы", а не в отчёт
|
||||
# о нарушениях.
|
||||
related_candidates.append(candidate)
|
||||
|
||||
if (i + 1) % 10 == 0:
|
||||
logger.info(f"Проверено фрагментов: {i + 1}/{len(fragments)}")
|
||||
@@ -146,7 +157,12 @@ def check_plagiarism(
|
||||
from app.scoring import aggregate_results
|
||||
|
||||
result = aggregate_results(
|
||||
level1_matches, level2_matches, semantic_matches, len(fragments), full_text=text
|
||||
level1_matches,
|
||||
level2_matches,
|
||||
semantic_matches,
|
||||
len(fragments),
|
||||
full_text=text,
|
||||
related_candidates=related_candidates,
|
||||
)
|
||||
|
||||
# Сохранить результат
|
||||
|
||||
Reference in New Issue
Block a user