Spaces:
Running on Zero
Running on Zero
Upload app.py
Browse files
app.py
CHANGED
|
@@ -3788,13 +3788,15 @@ UI_CONFIG = {
|
|
| 3788 |
"ONLINE_RERANK_MAX_CPU": 12,
|
| 3789 |
# Smarter selection for the same 12 expensive BGE slots: accuracy up, latency flat.
|
| 3790 |
"CHEAP_CANDIDATES_PER_BOOK": 3,
|
| 3791 |
-
# Set-valued questions
|
| 3792 |
-
#
|
| 3793 |
-
#
|
| 3794 |
-
|
| 3795 |
-
"
|
| 3796 |
-
"
|
| 3797 |
-
"
|
|
|
|
|
|
|
| 3798 |
"MAX_RERANKED_PER_BOOK": 2,
|
| 3799 |
"DIVERSE_CANDIDATE_SELECTION": True,
|
| 3800 |
"MIN_RETRIEVER_AGREEMENT": 2,
|
|
@@ -6278,74 +6280,170 @@ class ProfessionalEvidenceEngine:
|
|
| 6278 |
per_book_limit=max(1,min(4,int(filters.get("evidence_count",1) or 1))); allowed_df=self.df.iloc[answer_allowed]
|
| 6279 |
|
| 6280 |
# The visible evidence_count is a presentation limit, not an answer-completeness
|
| 6281 |
-
# limit.
|
| 6282 |
-
# sibling records in the same book, so deepen recall only for the strongest
|
| 6283 |
-
# books while leaving normal questions at the original small per-book budget.
|
| 6284 |
query_structure = analyze_direct_answer_intent_ui(query, lang)
|
| 6285 |
generic_request_type = clean_ui(query_structure.get("generic_request_type", "")).casefold()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6286 |
set_valued_request = generic_request_type in {"list", "components", "conditions", "pillars", "duties"}
|
| 6287 |
|
| 6288 |
base_cheap_per_book=max(
|
| 6289 |
per_book_limit,
|
| 6290 |
int(UI_CONFIG.get("CHEAP_CANDIDATES_PER_BOOK",3)),
|
| 6291 |
)
|
| 6292 |
-
|
| 6293 |
-
|
| 6294 |
-
|
| 6295 |
-
|
| 6296 |
-
|
| 6297 |
-
|
| 6298 |
-
|
| 6299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6300 |
|
| 6301 |
grouped_books=[]
|
| 6302 |
for bid, group in allowed_df.groupby("book_id", sort=False):
|
| 6303 |
local=np.asarray(group.index.tolist(), dtype=int)
|
| 6304 |
if not len(local):
|
| 6305 |
continue
|
| 6306 |
-
|
| 6307 |
-
grouped_books.append((str(bid), local, best_score))
|
| 6308 |
-
|
| 6309 |
-
deep_books=set()
|
| 6310 |
-
if set_valued_request:
|
| 6311 |
-
deep_books={
|
| 6312 |
-
bid
|
| 6313 |
-
for bid, _, _ in sorted(
|
| 6314 |
-
grouped_books,
|
| 6315 |
-
key=lambda row: row[2],
|
| 6316 |
-
reverse=True,
|
| 6317 |
-
)[:deep_book_limit]
|
| 6318 |
-
}
|
| 6319 |
|
| 6320 |
candidate_pool=set(exact_indices)
|
| 6321 |
preliminary_book_best=[]
|
| 6322 |
answer_take_by_book={}
|
| 6323 |
for bid, local, _ in grouped_books:
|
| 6324 |
-
|
| 6325 |
-
|
| 6326 |
-
if set_valued_request and bid in deep_books
|
| 6327 |
-
else base_cheap_per_book
|
| 6328 |
-
)
|
| 6329 |
-
take=min(len(local),take_limit)
|
| 6330 |
-
answer_take_by_book[bid]=take_limit
|
| 6331 |
if take:
|
| 6332 |
best=local[np.argsort(-pre[local])[:take]]
|
| 6333 |
candidate_pool.update(map(int,best))
|
| 6334 |
preliminary_book_best.append(int(best[0]))
|
| 6335 |
-
|
| 6336 |
candidate_pool.update(global_set)
|
| 6337 |
-
|
| 6338 |
-
|
| 6339 |
-
len(preliminary_book_best),
|
| 6340 |
-
)
|
| 6341 |
if set_valued_request:
|
| 6342 |
-
|
| 6343 |
-
|
| 6344 |
-
|
| 6345 |
-
|
| 6346 |
-
|
| 6347 |
-
)
|
| 6348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6349 |
ranked_pool=sorted(candidate_pool,key=lambda i:float(pre[i]),reverse=True)
|
| 6350 |
graph_seeds=ranked_pool[:min(12, len(ranked_pool))]
|
| 6351 |
graph_candidates, graph_reasons = self.kb_graph.expand(
|
|
@@ -6354,7 +6452,19 @@ class ProfessionalEvidenceEngine:
|
|
| 6354 |
)
|
| 6355 |
candidate_pool.update(graph_candidates)
|
| 6356 |
ranked_pool=sorted(candidate_pool,key=lambda i:float(pre[i]),reverse=True)
|
| 6357 |
-
candidates=np.asarray(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6358 |
rerank_cap=int(UI_CONFIG.get("ONLINE_RERANK_MAX_CPU",12)) if self._model_device=="cpu" else len(candidates)
|
| 6359 |
arrays_by_name={"word":sw,"char":sc,"bm25":bm,"dense":dn,"fusion":pre}
|
| 6360 |
promotion_order,promotion_reasons=self._diverse_promotion_order(candidates,exact_indices,arrays_by_name,rerank_cap)
|
|
@@ -6384,6 +6494,40 @@ class ProfessionalEvidenceEngine:
|
|
| 6384 |
for idx, reasons in graph_reasons.items():
|
| 6385 |
promotion_reasons.setdefault(int(idx), [])
|
| 6386 |
promotion_reasons[int(idx)] = sorted(set(promotion_reasons[int(idx)]) | set(reasons))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6387 |
rerank_indices=np.asarray(promotion_order,dtype=int); reranked_set=set(map(int,rerank_indices))
|
| 6388 |
top_sets={name:set(map(int,self._top_indices(arr,allowed,min(per_retriever,24)))) for name,arr in arrays_by_name.items()}
|
| 6389 |
|
|
@@ -6487,14 +6631,33 @@ class ProfessionalEvidenceEngine:
|
|
| 6487 |
if not items:
|
| 6488 |
missing_books.append(bid); continue
|
| 6489 |
|
| 6490 |
-
# Keep
|
| 6491 |
-
#
|
| 6492 |
-
# the strongest books receive deeper sibling-record coverage.
|
| 6493 |
answer_take=int(answer_take_by_book.get(str(bid),base_cheap_per_book))
|
| 6494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6495 |
answer_item = dict(item)
|
| 6496 |
answer_item["book_rank"] = answer_rank
|
| 6497 |
answer_item["book_records_searched"] = int(self.book_record_counts.get(bid,0))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6498 |
answer_pool.append(answer_item)
|
| 6499 |
|
| 6500 |
chosen = items[:per_book_limit]
|
|
@@ -6529,7 +6692,10 @@ class ProfessionalEvidenceEngine:
|
|
| 6529 |
"index_only_candidates_skipped":int(index_only_rows_skipped),"reranked_candidates":int(len(rerank_indices)),
|
| 6530 |
"cheap_candidates_per_book":int(base_cheap_per_book),"answer_pool_count":len(answer_pool),"diverse_candidate_selection":True,"kb_native":self.kb_native,
|
| 6531 |
"generic_request_type":generic_request_type,"set_valued_retrieval_expansion":bool(set_valued_request),
|
| 6532 |
-
"
|
|
|
|
|
|
|
|
|
|
| 6533 |
"top_score":float(max((x["score"] for x in all_items),default=0.0)),
|
| 6534 |
"latency":time.perf_counter()-started,"array_latency":arrays_sec,"rerank_latency":rerank_sec,
|
| 6535 |
"cache_hit":False,"minimum_score":requested,"retrieval_mode":mode,
|
|
|
|
| 3788 |
"ONLINE_RERANK_MAX_CPU": 12,
|
| 3789 |
# Smarter selection for the same 12 expensive BGE slots: accuracy up, latency flat.
|
| 3790 |
"CHEAP_CANDIDATES_PER_BOOK": 3,
|
| 3791 |
+
# Set-valued questions may distribute one answer across nearby source records.
|
| 3792 |
+
# Do not deepen whole books blindly. Instead, reserve a few reranker slots for
|
| 3793 |
+
# semantically qualified sibling records near a source-local set seed.
|
| 3794 |
+
"SET_RECALL_MAX_SEEDS": 8,
|
| 3795 |
+
"SET_RECALL_SEED_PER_BOOK": 2,
|
| 3796 |
+
"SET_RECALL_PAGE_RADIUS": 4,
|
| 3797 |
+
"SET_RECALL_MAX_SIBLINGS": 12,
|
| 3798 |
+
"SET_RECALL_SIBLINGS_PER_BOOK": 8,
|
| 3799 |
+
"SET_RECALL_RERANK_RESERVE": 6,
|
| 3800 |
"MAX_RERANKED_PER_BOOK": 2,
|
| 3801 |
"DIVERSE_CANDIDATE_SELECTION": True,
|
| 3802 |
"MIN_RETRIEVER_AGREEMENT": 2,
|
|
|
|
| 6280 |
per_book_limit=max(1,min(4,int(filters.get("evidence_count",1) or 1))); allowed_df=self.df.iloc[answer_allowed]
|
| 6281 |
|
| 6282 |
# The visible evidence_count is a presentation limit, not an answer-completeness
|
| 6283 |
+
# limit. Ordinary questions keep the original top-k-per-book behavior.
|
|
|
|
|
|
|
| 6284 |
query_structure = analyze_direct_answer_intent_ui(query, lang)
|
| 6285 |
generic_request_type = clean_ui(query_structure.get("generic_request_type", "")).casefold()
|
| 6286 |
+
generic_subject_terms = [
|
| 6287 |
+
clean_ui(value)
|
| 6288 |
+
for value in (query_structure.get("generic_subject_terms", []) or [])
|
| 6289 |
+
if clean_ui(value)
|
| 6290 |
+
]
|
| 6291 |
set_valued_request = generic_request_type in {"list", "components", "conditions", "pillars", "duties"}
|
| 6292 |
|
| 6293 |
base_cheap_per_book=max(
|
| 6294 |
per_book_limit,
|
| 6295 |
int(UI_CONFIG.get("CHEAP_CANDIDATES_PER_BOOK",3)),
|
| 6296 |
)
|
| 6297 |
+
|
| 6298 |
+
def _set_recall_page_number(row) -> int | None:
|
| 6299 |
+
match = re.search(r"\d+", str(getattr(row, "page_number", "") or ""))
|
| 6300 |
+
return int(match.group()) if match else None
|
| 6301 |
+
|
| 6302 |
+
def _set_recall_operator_cue(row) -> bool:
|
| 6303 |
+
if not set_valued_request:
|
| 6304 |
+
return False
|
| 6305 |
+
structural = " ".join(
|
| 6306 |
+
str(value or "")
|
| 6307 |
+
for value in (
|
| 6308 |
+
getattr(row, "ruling", "") if ar else getattr(row, "ruling_en", ""),
|
| 6309 |
+
getattr(row, "title", "") if ar else getattr(row, "title_en", ""),
|
| 6310 |
+
getattr(row, "question", "") if ar else getattr(row, "question_en", ""),
|
| 6311 |
+
getattr(row, "chapter", "") if ar else getattr(row, "chapter_en", ""),
|
| 6312 |
+
)
|
| 6313 |
+
)
|
| 6314 |
+
normalized = norm_ar_ui(structural) if ar else norm_en_ui(structural)
|
| 6315 |
+
if generic_request_type == "conditions":
|
| 6316 |
+
patterns = (
|
| 6317 |
+
(r"(?:^|\s)(?:شرط|شروط|اشتراط|يشترط|الاستطاعة|القدرة)(?:\s|$)",)
|
| 6318 |
+
if ar
|
| 6319 |
+
else (r"\b(?:condition|conditions|requirement|requirements|capacity|ability)\b",)
|
| 6320 |
+
)
|
| 6321 |
+
elif generic_request_type == "pillars":
|
| 6322 |
+
patterns = (
|
| 6323 |
+
(r"(?:^|\s)(?:ركن|اركان|أركان)(?:\s|$)",)
|
| 6324 |
+
if ar
|
| 6325 |
+
else (r"\b(?:pillar|pillars)\b",)
|
| 6326 |
+
)
|
| 6327 |
+
elif generic_request_type == "duties":
|
| 6328 |
+
patterns = (
|
| 6329 |
+
(r"(?:^|\s)(?:واجب|واجبات)(?:\s|$)",)
|
| 6330 |
+
if ar
|
| 6331 |
+
else (r"\b(?:duty|duties|required|obligatory)\b",)
|
| 6332 |
+
)
|
| 6333 |
+
else:
|
| 6334 |
+
patterns = (
|
| 6335 |
+
(r"(?:^|\s)(?:مكونات|اجزاء|أجزاء|عناصر|قائمة)(?:\s|$)",)
|
| 6336 |
+
if ar
|
| 6337 |
+
else (r"\b(?:components?|parts?|items?|list)\b",)
|
| 6338 |
+
)
|
| 6339 |
+
return any(re.search(pattern, normalized, re.I) for pattern in patterns)
|
| 6340 |
+
|
| 6341 |
+
def _set_recall_subject_bound(row) -> bool:
|
| 6342 |
+
if not generic_subject_terms:
|
| 6343 |
+
return True
|
| 6344 |
+
scope = " ".join(
|
| 6345 |
+
str(value or "")
|
| 6346 |
+
for value in (
|
| 6347 |
+
getattr(row, "question", "") if ar else getattr(row, "question_en", ""),
|
| 6348 |
+
getattr(row, "title", "") if ar else getattr(row, "title_en", ""),
|
| 6349 |
+
getattr(row, "chapter", "") if ar else getattr(row, "chapter_en", ""),
|
| 6350 |
+
getattr(row, "answer", "") if ar else getattr(row, "answer_en", ""),
|
| 6351 |
+
getattr(row, "answer_short", "") if ar else getattr(row, "answer_short_en", ""),
|
| 6352 |
+
getattr(row, "answer_detailed", "") if ar else getattr(row, "answer_detailed_en", ""),
|
| 6353 |
+
getattr(row, "answer_evidence", "") if ar else getattr(row, "answer_evidence_en", ""),
|
| 6354 |
+
)
|
| 6355 |
+
)
|
| 6356 |
+
probe = " ".join(generic_subject_terms)
|
| 6357 |
+
return topic_overlap(probe, scope, lang) >= 0.46
|
| 6358 |
|
| 6359 |
grouped_books=[]
|
| 6360 |
for bid, group in allowed_df.groupby("book_id", sort=False):
|
| 6361 |
local=np.asarray(group.index.tolist(), dtype=int)
|
| 6362 |
if not len(local):
|
| 6363 |
continue
|
| 6364 |
+
grouped_books.append((str(bid), local, float(np.max(pre[local]))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6365 |
|
| 6366 |
candidate_pool=set(exact_indices)
|
| 6367 |
preliminary_book_best=[]
|
| 6368 |
answer_take_by_book={}
|
| 6369 |
for bid, local, _ in grouped_books:
|
| 6370 |
+
take=min(len(local),base_cheap_per_book)
|
| 6371 |
+
answer_take_by_book[bid]=base_cheap_per_book
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6372 |
if take:
|
| 6373 |
best=local[np.argsort(-pre[local])[:take]]
|
| 6374 |
candidate_pool.update(map(int,best))
|
| 6375 |
preliminary_book_best.append(int(best[0]))
|
|
|
|
| 6376 |
candidate_pool.update(global_set)
|
| 6377 |
+
|
| 6378 |
+
set_seed_indices=[]
|
|
|
|
|
|
|
| 6379 |
if set_valued_request:
|
| 6380 |
+
seed_cap=max(1,int(UI_CONFIG.get("SET_RECALL_MAX_SEEDS",8)))
|
| 6381 |
+
seed_per_book=max(1,int(UI_CONFIG.get("SET_RECALL_SEED_PER_BOOK",2)))
|
| 6382 |
+
seed_counts=Counter()
|
| 6383 |
+
qualified=[]
|
| 6384 |
+
for idx in answer_allowed:
|
| 6385 |
+
idx=int(idx)
|
| 6386 |
+
row=self.df.iloc[idx]
|
| 6387 |
+
if not _set_recall_operator_cue(row):
|
| 6388 |
+
continue
|
| 6389 |
+
if not _set_recall_subject_bound(row):
|
| 6390 |
+
continue
|
| 6391 |
+
qualified.append(idx)
|
| 6392 |
+
for idx in sorted(qualified,key=lambda i:float(pre[int(i)]),reverse=True):
|
| 6393 |
+
bid=str(self.df.iloc[int(idx)].book_id)
|
| 6394 |
+
if seed_counts[bid]>=seed_per_book:
|
| 6395 |
+
continue
|
| 6396 |
+
set_seed_indices.append(int(idx))
|
| 6397 |
+
seed_counts[bid]+=1
|
| 6398 |
+
if len(set_seed_indices)>=seed_cap:
|
| 6399 |
+
break
|
| 6400 |
+
candidate_pool.update(set_seed_indices)
|
| 6401 |
+
|
| 6402 |
+
set_sibling_indices=[]
|
| 6403 |
+
set_sibling_distance={}
|
| 6404 |
+
if set_valued_request and set_seed_indices:
|
| 6405 |
+
page_radius=max(0,int(UI_CONFIG.get("SET_RECALL_PAGE_RADIUS",4)))
|
| 6406 |
+
sibling_cap=max(1,int(UI_CONFIG.get("SET_RECALL_MAX_SIBLINGS",12)))
|
| 6407 |
+
sibling_per_book=max(1,int(UI_CONFIG.get("SET_RECALL_SIBLINGS_PER_BOOK",8)))
|
| 6408 |
+
seed_pages_by_book=defaultdict(list)
|
| 6409 |
+
for idx in set_seed_indices:
|
| 6410 |
+
row=self.df.iloc[int(idx)]
|
| 6411 |
+
page=_set_recall_page_number(row)
|
| 6412 |
+
if page is not None:
|
| 6413 |
+
seed_pages_by_book[str(row.book_id)].append(page)
|
| 6414 |
+
|
| 6415 |
+
sibling_candidates=[]
|
| 6416 |
+
for bid, local, _ in grouped_books:
|
| 6417 |
+
seed_pages=seed_pages_by_book.get(str(bid), [])
|
| 6418 |
+
if not seed_pages:
|
| 6419 |
+
continue
|
| 6420 |
+
for idx in local:
|
| 6421 |
+
idx=int(idx)
|
| 6422 |
+
if idx in set_seed_indices:
|
| 6423 |
+
continue
|
| 6424 |
+
row=self.df.iloc[idx]
|
| 6425 |
+
if not _set_recall_operator_cue(row):
|
| 6426 |
+
continue
|
| 6427 |
+
page=_set_recall_page_number(row)
|
| 6428 |
+
if page is None:
|
| 6429 |
+
continue
|
| 6430 |
+
distance=min(abs(page-seed_page) for seed_page in seed_pages)
|
| 6431 |
+
if distance>page_radius:
|
| 6432 |
+
continue
|
| 6433 |
+
sibling_candidates.append((distance,-float(pre[idx]),idx,bid))
|
| 6434 |
+
|
| 6435 |
+
per_book_siblings=Counter()
|
| 6436 |
+
for distance,_,idx,bid in sorted(sibling_candidates):
|
| 6437 |
+
if per_book_siblings[str(bid)]>=sibling_per_book:
|
| 6438 |
+
continue
|
| 6439 |
+
set_sibling_indices.append(int(idx))
|
| 6440 |
+
set_sibling_distance[int(idx)]=int(distance)
|
| 6441 |
+
per_book_siblings[str(bid)]+=1
|
| 6442 |
+
if len(set_sibling_indices)>=sibling_cap:
|
| 6443 |
+
break
|
| 6444 |
+
candidate_pool.update(set_sibling_indices)
|
| 6445 |
+
|
| 6446 |
+
max_pool=max(int(UI_CONFIG.get("MAX_CANDIDATES",96)),len(preliminary_book_best))
|
| 6447 |
ranked_pool=sorted(candidate_pool,key=lambda i:float(pre[i]),reverse=True)
|
| 6448 |
graph_seeds=ranked_pool[:min(12, len(ranked_pool))]
|
| 6449 |
graph_candidates, graph_reasons = self.kb_graph.expand(
|
|
|
|
| 6452 |
)
|
| 6453 |
candidate_pool.update(graph_candidates)
|
| 6454 |
ranked_pool=sorted(candidate_pool,key=lambda i:float(pre[i]),reverse=True)
|
| 6455 |
+
candidates=np.asarray(
|
| 6456 |
+
sorted(
|
| 6457 |
+
set(preliminary_book_best)
|
| 6458 |
+
| set(exact_indices)
|
| 6459 |
+
| set(ranked_pool[:max_pool])
|
| 6460 |
+
| set(graph_candidates)
|
| 6461 |
+
| set(set_seed_indices)
|
| 6462 |
+
| set(set_sibling_indices),
|
| 6463 |
+
key=lambda i:float(pre[i]),
|
| 6464 |
+
reverse=True,
|
| 6465 |
+
),
|
| 6466 |
+
dtype=int,
|
| 6467 |
+
)
|
| 6468 |
rerank_cap=int(UI_CONFIG.get("ONLINE_RERANK_MAX_CPU",12)) if self._model_device=="cpu" else len(candidates)
|
| 6469 |
arrays_by_name={"word":sw,"char":sc,"bm25":bm,"dense":dn,"fusion":pre}
|
| 6470 |
promotion_order,promotion_reasons=self._diverse_promotion_order(candidates,exact_indices,arrays_by_name,rerank_cap)
|
|
|
|
| 6494 |
for idx, reasons in graph_reasons.items():
|
| 6495 |
promotion_reasons.setdefault(int(idx), [])
|
| 6496 |
promotion_reasons[int(idx)] = sorted(set(promotion_reasons[int(idx)]) | set(reasons))
|
| 6497 |
+
|
| 6498 |
+
set_recall_ranked=[]
|
| 6499 |
+
if set_valued_request and set_sibling_indices:
|
| 6500 |
+
reserve=min(
|
| 6501 |
+
max(0,int(UI_CONFIG.get("SET_RECALL_RERANK_RESERVE",6))),
|
| 6502 |
+
max(0,rerank_cap//2),
|
| 6503 |
+
)
|
| 6504 |
+
set_recall_ranked=sorted(
|
| 6505 |
+
set_sibling_indices,
|
| 6506 |
+
key=lambda i:(
|
| 6507 |
+
-int(set_sibling_distance.get(int(i),999)),
|
| 6508 |
+
float(pre[int(i)]),
|
| 6509 |
+
),
|
| 6510 |
+
reverse=True,
|
| 6511 |
+
)[:reserve]
|
| 6512 |
+
protected=set(map(int,exact_indices))|set(map(int,graph_ranked))|set(map(int,set_recall_ranked))
|
| 6513 |
+
for idx in set_recall_ranked:
|
| 6514 |
+
idx=int(idx)
|
| 6515 |
+
if idx in promotion_order:
|
| 6516 |
+
promotion_reasons.setdefault(idx,[])
|
| 6517 |
+
promotion_reasons[idx]=sorted(set(promotion_reasons[idx])|{"set_local_sibling"})
|
| 6518 |
+
continue
|
| 6519 |
+
if len(promotion_order)>=rerank_cap:
|
| 6520 |
+
removable=next(
|
| 6521 |
+
(j for j in reversed(promotion_order) if int(j) not in protected),
|
| 6522 |
+
None,
|
| 6523 |
+
)
|
| 6524 |
+
if removable is None:
|
| 6525 |
+
continue
|
| 6526 |
+
promotion_order.remove(removable)
|
| 6527 |
+
promotion_order.append(idx)
|
| 6528 |
+
promotion_reasons.setdefault(idx,[])
|
| 6529 |
+
promotion_reasons[idx]=sorted(set(promotion_reasons[idx])|{"set_local_sibling"})
|
| 6530 |
+
|
| 6531 |
rerank_indices=np.asarray(promotion_order,dtype=int); reranked_set=set(map(int,rerank_indices))
|
| 6532 |
top_sets={name:set(map(int,self._top_indices(arr,allowed,min(per_retriever,24)))) for name,arr in arrays_by_name.items()}
|
| 6533 |
|
|
|
|
| 6631 |
if not items:
|
| 6632 |
missing_books.append(bid); continue
|
| 6633 |
|
| 6634 |
+
# Keep the ordinary top-k internal pool, then append only source-local
|
| 6635 |
+
# semantic siblings that were explicitly selected above.
|
|
|
|
| 6636 |
answer_take=int(answer_take_by_book.get(str(bid),base_cheap_per_book))
|
| 6637 |
+
answer_items=list(items[:answer_take])
|
| 6638 |
+
if set_valued_request and set_sibling_indices:
|
| 6639 |
+
sibling_ids={
|
| 6640 |
+
str(self.df.iloc[int(i)].record_id)
|
| 6641 |
+
for i in set_sibling_indices
|
| 6642 |
+
if str(self.df.iloc[int(i)].book_id)==str(bid)
|
| 6643 |
+
}
|
| 6644 |
+
existing_ids={clean_ui(item.get("record_id","")) for item in answer_items}
|
| 6645 |
+
for item in items:
|
| 6646 |
+
rid=clean_ui(item.get("record_id",""))
|
| 6647 |
+
if rid in sibling_ids and rid not in existing_ids:
|
| 6648 |
+
answer_items.append(item)
|
| 6649 |
+
existing_ids.add(rid)
|
| 6650 |
+
|
| 6651 |
+
for answer_rank, item in enumerate(answer_items, start=1):
|
| 6652 |
answer_item = dict(item)
|
| 6653 |
answer_item["book_rank"] = answer_rank
|
| 6654 |
answer_item["book_records_searched"] = int(self.book_record_counts.get(bid,0))
|
| 6655 |
+
answer_item["set_local_sibling"] = bool(
|
| 6656 |
+
clean_ui(item.get("record_id","")) in {
|
| 6657 |
+
str(self.df.iloc[int(i)].record_id)
|
| 6658 |
+
for i in set_sibling_indices
|
| 6659 |
+
}
|
| 6660 |
+
)
|
| 6661 |
answer_pool.append(answer_item)
|
| 6662 |
|
| 6663 |
chosen = items[:per_book_limit]
|
|
|
|
| 6692 |
"index_only_candidates_skipped":int(index_only_rows_skipped),"reranked_candidates":int(len(rerank_indices)),
|
| 6693 |
"cheap_candidates_per_book":int(base_cheap_per_book),"answer_pool_count":len(answer_pool),"diverse_candidate_selection":True,"kb_native":self.kb_native,
|
| 6694 |
"generic_request_type":generic_request_type,"set_valued_retrieval_expansion":bool(set_valued_request),
|
| 6695 |
+
"set_recall_semantic_seeds":len(set_seed_indices),
|
| 6696 |
+
"set_recall_local_siblings":len(set_sibling_indices),
|
| 6697 |
+
"set_recall_reranked_siblings":len(set_recall_ranked),
|
| 6698 |
+
"set_recall_page_radius":int(UI_CONFIG.get("SET_RECALL_PAGE_RADIUS",4)),
|
| 6699 |
"top_score":float(max((x["score"] for x in all_items),default=0.0)),
|
| 6700 |
"latency":time.perf_counter()-started,"array_latency":arrays_sec,"rerank_latency":rerank_sec,
|
| 6701 |
"cache_hit":False,"minimum_score":requested,"retrieval_mode":mode,
|