Spaces:
Sleeping
Sleeping
Narayanaswamy Subramanian Anandathandavapuram
wrap respond in try/except for error visibility
0e6ac41 | import os | |
| import pickle | |
| import zipfile | |
| import requests | |
| import gradio as gr | |
| from langchain_community.vectorstores import FAISS | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| import numpy as np | |
| if not os.path.exists("faiss_store.zip"): | |
| import index_builder | |
| n = index_builder.build() | |
| print(f"Built index: {n} chunks") | |
| if not os.path.exists("faiss_store"): | |
| with zipfile.ZipFile("faiss_store.zip", "r") as zip_ref: | |
| zip_ref.extractall(".") | |
| embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2") | |
| vector_store = FAISS.load_local("faiss_store", embeddings, allow_dangerous_deserialization=True) | |
| with open("bm25_index.pkl", 'rb') as f: | |
| bm25_data = pickle.load(f) | |
| bm25 = bm25_data['bm25'] | |
| bm25_chunks = bm25_data['chunks'] | |
| bm25_sources = bm25_data['sources'] | |
| MODEL_NAME = "meta-llama/Llama-3.2-1B-Instruct" | |
| QUERY_EXPANSIONS = { | |
| "companies": "Genpact Netscribes Cheers Interactive FutureBridge Evalueserve Baxter", | |
| "company": "Genpact Netscribes Cheers FutureBridge Evalueserve Baxter", | |
| "worked": "employed served role Genpact Netscribes Cheers FutureBridge Evalueserve Baxter", | |
| "education": "degree qualification university college Walsh IIM Kozhikode ICT Mumbai", | |
| "skills": "expertise Python TensorFlow PyTorch LangChain AWS Azure GCP Databricks", | |
| "experience": "background Genpact Netscribes Cheers Evalueserve Baxter", | |
| "role": "Vice President AVP Senior Manager Manager Associate Executive", | |
| "projects": "programs initiatives GenAI Consumer Intelligence RGM MLOps", | |
| "genai": "generative ai llm rag large language model agentic", | |
| "architecture": "enterprise cloud modernization strategy governance", | |
| "consumer": "retail cpg fmcg intelligence insights analytics", | |
| "retail": "consumer cpg fmcg shopper measurement analytics", | |
| "pharma": "pharmaceutical life sciences healthcare biotech clinical", | |
| } | |
| def expand_keywords(query): | |
| expanded = query | |
| for word, expansion in QUERY_EXPANSIONS.items(): | |
| if word in query.lower().split(): | |
| expanded += " " + expansion | |
| return expanded.strip() | |
| def retrieve(query, k=20): | |
| faiss_docs = vector_store.similarity_search(query, k=k) | |
| expanded = expand_keywords(query) | |
| tokenized = expanded.lower().split() | |
| bm25_scores = bm25.get_scores(tokenized) | |
| top_indices = np.argsort(bm25_scores)[-k:][::-1] | |
| bm25_results = [(bm25_chunks[i], bm25_scores[i]) for i in top_indices if bm25_scores[i] > 0] | |
| rrf_scores = {} | |
| for rank, doc in enumerate(faiss_docs): | |
| rrf_scores[doc.page_content] = rrf_scores.get(doc.page_content, 0) + 1.0 / (60 + rank + 1) | |
| for rank, (chunk, score) in enumerate(bm25_results): | |
| rrf_scores[chunk] = rrf_scores.get(chunk, 0) + 1.0 / (60 + rank + 1) | |
| seen = set() | |
| merged = [] | |
| for chunk, _ in sorted(rrf_scores.items(), key=lambda x: -x[1]): | |
| if chunk not in seen: | |
| seen.add(chunk) | |
| merged.append(chunk) | |
| return merged[:k] | |
| def generate(query, context, history): | |
| hf_token = os.environ.get("HF_TOKEN") | |
| if not hf_token: | |
| return "Please add your HuggingFace token as a secret in Space settings." | |
| messages = [ | |
| {"role": "system", "content": "You are a Career History AI Agent answering questions about a professional's resume.\n\nRULES:\n1. ONLY mention facts present in the context blocks below.\n2. NEVER invent or guess company names, dates, roles, or metrics.\n3. If something is not in the context, say \"The available information does not mention this.\"\n4. Organize answers chronologically when possible.\n5. Distinguish employers, roles, projects, events, and certifications clearly.\n6. Include metrics (team sizes, dollar values, percentages, durations) when present.\n7. Answer directly as if speaking to a recruiter or hiring manager.\n8. When listing companies, name them explicitly (e.g. Genpact, Netscribes, Evalueserve, Baxter)."} | |
| ] | |
| for turn in history[-4:]: | |
| messages.append({"role": turn["role"], "content": turn["content"]}) | |
| messages.append({"role": "user", "content": f"CONTEXT BLOCKS:\n{context}\n\nQUESTION: {query}\n\nAnswer using ONLY the context blocks."}) | |
| payload = {"model": MODEL_NAME, "messages": messages, "max_tokens": 500} | |
| try: | |
| response = requests.post( | |
| "https://router.huggingface.co/v1/chat/completions", | |
| headers={"Authorization": f"Bearer {hf_token}"}, | |
| json=payload, timeout=120 | |
| ) | |
| if response.status_code == 503: | |
| return "Model is loading. Please try again in a few seconds." | |
| if response.status_code == 403: | |
| return "Access denied. Ensure your HF token has 'Make calls to inference providers' permission enabled at hf.co/settings/tokens." | |
| response.raise_for_status() | |
| return response.json()["choices"][0]["message"]["content"] | |
| except requests.exceptions.RequestException as e: | |
| return f"API request failed: {e}" | |
| def rag_chain(query, history): | |
| top_chunks = retrieve(query, k=8) | |
| context = "\n\n---\n\n".join(top_chunks) | |
| return generate(query, context, history) | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# Know more about my work experience/portfolio...") | |
| chatbot = gr.Chatbot(height=400, type="messages") | |
| msg = gr.Textbox(placeholder="Ask about Narayanaswamy's (Bala's) work experience...") | |
| clear = gr.Button("Clear") | |
| def respond(message, history): | |
| try: | |
| history = history or [] | |
| answer = rag_chain(message, history) | |
| history.append({"role": "user", "content": message}) | |
| history.append({"role": "assistant", "content": answer}) | |
| return "", history | |
| except Exception as e: | |
| import traceback | |
| tb = traceback.format_exc() | |
| err_history = list(history or []) | |
| err_history.append({"role": "user", "content": message}) | |
| err_history.append({"role": "assistant", "content": f"Error: {e}\n\n{tb}"}) | |
| return "", err_history | |
| msg.submit(respond, [msg, chatbot], [msg, chatbot], queue=False, api_name="chat") | |
| clear.click(lambda: [], None, chatbot, queue=False) | |
| demo.launch() | |