import json import math import gradio as gr import torch from sentence_transformers import SentenceTransformer, CrossEncoder, util HF_USERNAME = "anuragseven" # <-- set to your username, or the Space will fail to load # fine-tuned models (downloaded once from the Hub, then cached on the Space) bi = SentenceTransformer(f"{HF_USERNAME}/scifact-biencoder") ce = CrossEncoder(f"{HF_USERNAME}/scifact-crossencoder") # precomputed artifacts shipped in this repo -> no beir, no corpus download, # no startup embedding. Cold start is just "load three small files". with open("corpus.json") as f: corpus = json.load(f) # {doc_id: {"title": ..., "text": ...}} with open("ids.json") as f: ids = json.load(f) # ordered doc_ids aligned with emb rows emb = torch.load("doc_emb.pt", map_location="cpu") # normalized doc embeddings RERANK_K = 20 # dense candidates fed to the cross-encoder (was 50) def make_text(d): return (corpus[d].get("title", "") + " " + corpus[d].get("text", "")).strip() def search(query, top_k=5): if not query or not query.strip(): return "Enter a scientific claim or query." qe = bi.encode(query, normalize_embeddings=True, convert_to_tensor=True) hits = util.semantic_search(qe, emb, top_k=RERANK_K)[0] cand = [ids[h["corpus_id"]] for h in hits] scores = ce.predict([[query, make_text(c)] for c in cand]) order = sorted(range(len(cand)), key=lambda j: scores[j], reverse=True)[:int(top_k)] out = "" for r, j in enumerate(order, 1): c = cand[j] rel = 1.0 / (1.0 + math.exp(-float(scores[j]))) # sigmoid: logit -> 0..1 out += f"### {r}. {corpus[c]['title']}\n{corpus[c]['text'][:300]}...\n\n_relevance: {rel:.2f}_\n\n" return out EXAMPLES = [ ["Statins reduce LDL cholesterol levels.", 5], ["Aspirin reduces the risk of colorectal cancer.", 5], ["Vitamin D supplementation reduces respiratory infections.", 5], ["Smoking increases the risk of cardiovascular disease.", 5], ] gr.Interface(fn=search, inputs=[gr.Textbox(label="Scientific claim / query"), gr.Slider(1, 10, value=5, step=1, label="Results")], outputs=gr.Markdown(), examples=EXAMPLES, cache_examples=False, # click only fills the box; user presses Submit (clear feedback) title="SciFact Neural Search", description="Fine-tuned bi-encoder retrieval + cross-encoder re-ranking").launch(server_name="0.0.0.0", server_port=7860)