99import requests
1010
1111from memos .log import get_logger
12- from memos .utils import timed
12+ from memos .utils import timed_with_status
1313
1414from .base import BaseReranker
1515from .concat import concat_original_source
@@ -119,8 +119,12 @@ def __init__(
119119 self .warn_unknown_filter_keys = bool (warn_unknown_filter_keys )
120120 self ._warned_missing_keys : set [str ] = set ()
121121
122- @timed (
123- log = True , log_prefix = "model_timed_rerank" , log_extra_args = {"model_name_or_path" : "reranker" }
122+ @timed_with_status (
123+ log_prefix = "model_timed_rerank" ,
124+ log_extra_args = {"model_name_or_path" : "reranker" },
125+ fallback = lambda exc , self , query , graph_results , top_k , * a , ** kw : [
126+ (item , 0.0 ) for item in graph_results [:top_k ]
127+ ],
124128 )
125129 def rerank (
126130 self ,
@@ -150,6 +154,7 @@ def rerank(
150154 list[tuple[TextualMemoryItem, float]]
151155 Re-ranked items with scores, sorted descending by score.
152156 """
157+
153158 if not graph_results :
154159 return []
155160
@@ -173,63 +178,54 @@ def rerank(
173178 headers = {"Content-Type" : "application/json" , ** self .headers_extra }
174179 payload = {"model" : self .model , "query" : query , "documents" : documents }
175180
176- try :
177- # Make the HTTP request to the reranker service
178- resp = requests .post (
179- self .reranker_url , headers = headers , json = payload , timeout = self .timeout
180- )
181- resp .raise_for_status ()
182- data = resp .json ()
183-
184- scored_items : list [tuple [TextualMemoryItem , float ]] = []
185-
186- if "results" in data :
187- # Format:
188- # dict("results": [{"index": int, "relevance_score": float},
189- # ...])
190- rows = data .get ("results" , [])
191- for r in rows :
192- idx = r .get ("index" )
193- # The returned index refers to 'documents' (i.e., our 'pairs' order),
194- # so we must map it back to the original graph_results index.
195- if isinstance (idx , int ) and 0 <= idx < len (graph_results ):
196- raw_score = float (r .get ("relevance_score" , r .get ("score" , 0.0 )))
197- item = graph_results [idx ]
198- # generic boost
199- score = self ._apply_boost_generic (item , raw_score , search_priority )
200- scored_items .append ((item , score ))
201-
202- scored_items .sort (key = lambda x : x [1 ], reverse = True )
203- return scored_items [: min (top_k , len (scored_items ))]
204-
205- elif "data" in data :
206- # Format: {"data": [{"score": float}, ...]} aligned by list order
207- rows = data .get ("data" , [])
208- # Build a list of scores aligned with our 'documents' (pairs)
209- score_list = [float (r .get ("score" , 0.0 )) for r in rows ]
210-
211- if len (score_list ) < len (graph_results ):
212- score_list += [0.0 ] * (len (graph_results ) - len (score_list ))
213- elif len (score_list ) > len (graph_results ):
214- score_list = score_list [: len (graph_results )]
215-
216- scored_items = []
217- for item , raw_score in zip (graph_results , score_list , strict = False ):
181+ # Make the HTTP request to the reranker service
182+ resp = requests .post (self .reranker_url , headers = headers , json = payload , timeout = self .timeout )
183+ resp .raise_for_status ()
184+ data = resp .json ()
185+
186+ scored_items : list [tuple [TextualMemoryItem , float ]] = []
187+
188+ if "results" in data :
189+ # Format:
190+ # dict("results": [{"index": int, "relevance_score": float},
191+ # ...])
192+ rows = data .get ("results" , [])
193+ for r in rows :
194+ idx = r .get ("index" )
195+ # The returned index refers to 'documents' (i.e., our 'pairs' order),
196+ # so we must map it back to the original graph_results index.
197+ if isinstance (idx , int ) and 0 <= idx < len (graph_results ):
198+ raw_score = float (r .get ("relevance_score" , r .get ("score" , 0.0 )))
199+ item = graph_results [idx ]
200+ # generic boost
218201 score = self ._apply_boost_generic (item , raw_score , search_priority )
219202 scored_items .append ((item , score ))
220203
221- scored_items .sort (key = lambda x : x [1 ], reverse = True )
222- return scored_items [: min (top_k , len (scored_items ))]
204+ scored_items .sort (key = lambda x : x [1 ], reverse = True )
205+ return scored_items [: min (top_k , len (scored_items ))]
206+
207+ elif "data" in data :
208+ # Format: {"data": [{"score": float}, ...]} aligned by list order
209+ rows = data .get ("data" , [])
210+ # Build a list of scores aligned with our 'documents' (pairs)
211+ score_list = [float (r .get ("score" , 0.0 )) for r in rows ]
212+
213+ if len (score_list ) < len (graph_results ):
214+ score_list += [0.0 ] * (len (graph_results ) - len (score_list ))
215+ elif len (score_list ) > len (graph_results ):
216+ score_list = score_list [: len (graph_results )]
223217
224- else :
225- # Unexpected response schema: return a 0.0-scored fallback of the first top_k valid docs
226- # Note: we use 'pairs' to keep alignment with valid (string) docs.
227- return [( item , 0.0 ) for item in graph_results [: top_k ]]
218+ scored_items = []
219+ for item , raw_score in zip ( graph_results , score_list , strict = False ):
220+ score = self . _apply_boost_generic ( item , raw_score , search_priority )
221+ scored_items . append (( item , score ))
228222
229- except Exception as e :
230- # Network error, timeout, JSON decode error, etc.
231- # Degrade gracefully by returning first top_k valid docs with 0.0 score.
232- logger .error (f"[HTTPBGEReranker] request failed: { e } " )
223+ scored_items .sort (key = lambda x : x [1 ], reverse = True )
224+ return scored_items [: min (top_k , len (scored_items ))]
225+
226+ else :
227+ # Unexpected response schema: return a 0.0-scored fallback of the first top_k valid docs
228+ # Note: we use 'pairs' to keep alignment with valid (string) docs.
233229 return [(item , 0.0 ) for item in graph_results [:top_k ]]
234230
235231 def _get_attr_or_key (self , obj : Any , key : str ) -> Any :
0 commit comments