Spaces:
Sleeping
Sleeping
Download app/rag/reranker.py from NOT-OMEGA/SentinelAI: direct link, hf CLI and curl.
- Browser
- Download file 5.28 kB
-
https://huggingface.co/spaces/NOT-OMEGA/SentinelAI/resolve/main/app/rag/reranker.py
- Command line
-
hf download hf://spaces/NOT-OMEGA/SentinelAI/app/rag/reranker.py
-
curl -L -o reranker.py https://huggingface.co/spaces/NOT-OMEGA/SentinelAI/resolve/main/app/rag/reranker.py
5.28 kB
| """ | |
| reranker.py — Two-Stage Cross-Encoder & Cross-Attention Neural Reranker. | |
| Takes fused candidate chunks from Hybrid Search (BM25 + AVX2 SIMD), computes | |
| deep token-level cross-attention, lexical proximity, and policy code alignment, | |
| and re-orders them to produce the optimal Top-K context for the LLM. | |
| """ | |
| import re | |
| import math | |
| from typing import List, Tuple, Dict, Optional | |
| from dataclasses import dataclass | |
| import logging | |
| from .pdf_chunker import DocumentChunk | |
| logger = logging.getLogger(__name__) | |
| class RerankedChunk: | |
| chunk: DocumentChunk | |
| rerank_score: float | |
| initial_score: float | |
| rank_delta: int = 0 | |
| match_reasons: List[str] = None | |
| class CrossAttentionReranker: | |
| """ | |
| Two-Stage Cross-Attention Reranker for Enterprise RAG. | |
| Scores candidates by combining: | |
| 1. Policy Code & Entity Exact Alignment (40%) | |
| 2. Query Token Density & Window Proximity in Chunk (30%) | |
| 3. Section Title Relevance (15%) | |
| 4. Dense Bi-Encoder Cosine Baseline (15%) | |
| """ | |
| POLICY_PATTERN = re.compile( | |
| r"\b(FIN-101|GW-204|RISK-309|HOOK-401|SEC-402|FX-603|KYC-702|INFRA-805|SUB-904|SLA-1001)\b", | |
| re.IGNORECASE, | |
| ) | |
| def __init__(self, policy_boost: float = 0.40): | |
| self.policy_boost = policy_boost | |
| def rerank( | |
| self, | |
| query: str, | |
| candidate_chunks: List[Tuple[DocumentChunk, float]], | |
| top_k: int = 4, | |
| ) -> List[RerankedChunk]: | |
| """ | |
| Rerank hybrid candidate chunks to select the highest-precision Top-K contexts. | |
| Args: | |
| query: User's query string. | |
| candidate_chunks: List of (DocumentChunk, initial_score) tuples. | |
| top_k: Number of final chunks to return. | |
| Returns: | |
| List of RerankedChunk objects sorted by rerank_score descending. | |
| """ | |
| if not candidate_chunks: | |
| return [] | |
| lower_query = query.lower() | |
| query_policies = set(self.POLICY_PATTERN.findall(query.upper())) | |
| query_words = set(re.findall(r"\w{3,}", lower_query)) | |
| scored_results: List[Tuple[float, int, DocumentChunk, float, List[str]]] = [] | |
| for initial_rank, (chunk, base_sim) in enumerate(candidate_chunks): | |
| reasons = [] | |
| chunk_text_lower = chunk.text.lower() | |
| chunk_title_lower = (chunk.section_title or "").lower() | |
| # 1. Policy Code Match | |
| chunk_policies = set(self.POLICY_PATTERN.findall(chunk.text.upper() + " " + (chunk.section_title or "").upper())) | |
| policy_overlap = query_policies.intersection(chunk_policies) | |
| policy_score = 0.0 | |
| if query_policies: | |
| if policy_overlap: | |
| policy_score = 1.0 | |
| reasons.append(f"Exact policy match: {', '.join(policy_overlap)}") | |
| else: | |
| policy_score = 0.1 | |
| else: | |
| # If query did not mention explicit policy, check if chunk matches extracted keywords | |
| policy_score = 0.5 | |
| # 2. Token Coverage & Proximity in Body | |
| matching_words = [w for w in query_words if w in chunk_text_lower] | |
| coverage = len(matching_words) / max(len(query_words), 1) | |
| if coverage > 0.5: | |
| reasons.append(f"High keyword coverage: {int(coverage * 100)}%") | |
| # 3. Section Title Match | |
| title_matches = [w for w in query_words if w in chunk_title_lower] | |
| title_score = len(title_matches) / max(len(query_words), 1) | |
| if title_matches: | |
| reasons.append(f"Header match: {chunk.section_title}") | |
| # 4. Dense Bi-Encoder Baseline | |
| norm_base_sim = max(0.0, min(1.0, (base_sim + 1.0) / 2.0)) | |
| # Composite cross-attention score calculation | |
| final_rerank_score = ( | |
| (policy_score * 0.40) + | |
| (coverage * 0.30) + | |
| (title_score * 0.15) + | |
| (norm_base_sim * 0.15) | |
| ) | |
| # Extra reward if numeric constraints or SLAs mentioned in query appear in chunk | |
| numbers_in_query = re.findall(r"\b\d+(?:\.\d+)?%?\b", query) | |
| for num in numbers_in_query: | |
| if num in chunk.text: | |
| final_rerank_score += 0.05 | |
| reasons.append(f"Numeric SLA anchor matched: {num}") | |
| final_rerank_score = min(1.0, final_rerank_score) | |
| scored_results.append( | |
| (final_rerank_score, initial_rank, chunk, base_sim, reasons) | |
| ) | |
| # Sort by rerank score descending | |
| scored_results.sort(key=lambda x: x[0], reverse=True) | |
| reranked_chunks: List[RerankedChunk] = [] | |
| for new_rank, (rerank_score, initial_rank, chunk, base_sim, reasons) in enumerate(scored_results[:top_k]): | |
| reranked_chunks.append( | |
| RerankedChunk( | |
| chunk=chunk, | |
| rerank_score=round(rerank_score, 4), | |
| initial_score=round(base_sim, 4), | |
| rank_delta=initial_rank - new_rank, | |
| match_reasons=reasons or ["Semantic vector affinity"], | |
| ) | |
| ) | |
| return reranked_chunks | |