| from __future__ import annotations |
|
|
| from sentence_transformers import CrossEncoder |
|
|
|
|
| class LegalReranker: |
|
|
| def __init__( |
| self, |
| model_name: str = "BAAI/bge-reranker-large" |
| ): |
|
|
| self.model = CrossEncoder( |
| model_name, |
| max_length=512 |
| ) |
|
|
| |
| |
| |
|
|
| def build_rerank_query( |
| self, |
| query: str, |
| analysis=None |
| ) -> str: |
|
|
| if analysis is None: |
| return query |
|
|
| parts = [ |
| f"User Query: {query}" |
| ] |
|
|
| if getattr( |
| analysis, |
| "offence", |
| None |
| ): |
| parts.append( |
| f"Legal Offence: {analysis.offence}" |
| ) |
|
|
| if getattr( |
| analysis, |
| "intent", |
| None |
| ): |
| parts.append( |
| f"Intent: {analysis.intent}" |
| ) |
|
|
| return "\n".join(parts) |
|
|
| |
| |
| |
|
|
| def legal_boost( |
| self, |
| score: float, |
| text: str, |
| analysis=None |
| ) -> float: |
|
|
| if analysis is None: |
| return score |
|
|
| text = text.lower() |
|
|
| boost = 0.0 |
|
|
| offence = getattr( |
| analysis, |
| "offence", |
| None |
| ) |
|
|
| intent = getattr( |
| analysis, |
| "intent", |
| None |
| ) |
|
|
| |
| if offence: |
|
|
| if offence.lower() in text: |
| boost += 0.15 |
|
|
| |
| if intent == "punishment": |
|
|
| if "shall be punished" in text: |
| boost += 0.25 |
|
|
| if "punishment" in text: |
| boost += 0.10 |
|
|
| if "imprisonment" in text: |
| boost += 0.05 |
|
|
| |
| elif intent == "evidence": |
|
|
| if "evidence" in text: |
| boost += 0.15 |
|
|
| |
| elif intent == "procedure": |
|
|
| if "procedure" in text: |
| boost += 0.15 |
|
|
| return score + boost |
|
|
| |
| |
| |
|
|
| def rerank( |
| self, |
| query: str, |
| points, |
| top_k: int = 5, |
| analysis=None |
| ): |
|
|
| if not points: |
| return [] |
|
|
| rerank_query = self.build_rerank_query( |
| query=query, |
| analysis=analysis |
| ) |
|
|
| pairs = [] |
|
|
| point_texts = [] |
|
|
| for point in points: |
|
|
| payload = point.payload |
|
|
| text = ( |
| payload.get( |
| "enriched_text" |
| ) |
| or payload.get( |
| "text", |
| "" |
| ) |
| ) |
|
|
| point_texts.append(text) |
|
|
| pairs.append( |
| ( |
| rerank_query, |
| text |
| ) |
| ) |
|
|
| scores = self.model.predict( |
| pairs, |
| show_progress_bar=False |
| ) |
|
|
| ranked = [] |
|
|
| for point, score, text in zip( |
| points, |
| scores, |
| point_texts |
| ): |
|
|
| final_score = self.legal_boost( |
| score=float(score), |
| text=text, |
| analysis=analysis |
| ) |
|
|
| ranked.append( |
| { |
| "point": point, |
| "rerank_score": float(score), |
| "final_score": float(final_score) |
| } |
| ) |
|
|
| ranked.sort( |
| key=lambda x: x["final_score"], |
| reverse=True |
| ) |
|
|
| results = [ |
| item["point"] |
| for item in ranked[:top_k] |
| ] |
|
|
| |
| |
| |
|
|
| print("\n" + "=" * 80) |
| print("RERANK RESULTS") |
| print("=" * 80) |
|
|
| for rank, item in enumerate( |
| ranked[:top_k], |
| start=1 |
| ): |
|
|
| point = item["point"] |
|
|
| print( |
| f"{rank}. " |
| f"{point.payload.get('chunk_id')} " |
| f"| rerank={item['rerank_score']:.4f} " |
| f"| final={item['final_score']:.4f}" |
| ) |
|
|
| print("=" * 80) |
|
|
| return results |