File size: 3,783 Bytes
b13d185 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
import os
from huggingface_hub import InferenceClient
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableLambda
# =====================================================
# 1. INITIALIZATION SECTION (run ONCE)
# =====================================================
HF_API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN")
if not HF_API_TOKEN:
raise RuntimeError("Set HUGGINGFACE_API_TOKEN.")
MODEL_NAME = "" # When in use insert model name as parameter here
# Initialize remote LLM client ONCE
client = InferenceClient(
model=MODEL_NAME,
token=HF_API_TOKEN
)
# LLM wrapper
def hf_llm(prompt: str) -> str:
response = client.chat_completion(
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
temperature=0.3
)
return response.choices[0].message["content"]
# -----------------------------
# Vectorstore initialization
# -----------------------------
def init_vectorstore():
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
vector_store_path = os.path.join(base_dir, "data", "vectorstores")
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vectorstore = FAISS.load_local(
folder_path=vector_store_path,
embeddings=embeddings,
allow_dangerous_deserialization=True,
)
return vectorstore
vectorstore = init_vectorstore()
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# =====================================================
# 2. BUILD RAG ANALYSIS CHAIN (no re-init)
# =====================================================
def build_analysis_chain(retriever, llm_callable):
"""
retriever -> FAISS retriever already initialized
llm_callable -> function that takes string prompt and returns string
"""
vectorstore = init_vectorstore()
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
prompt = ChatPromptTemplate.from_template(
"""
You are a professional Resume Analyst AI.
Return a professional summary and hold a conversation keeping the following metrics in mind:
{{
"job_fit_score": 0-100,
"fit_summary": "<3 sentence summary>",
"strengths": ["..."],
"missing_skills": ["..."],
"recommendations": ["..."]
}}
RETRIEVED RESUME CONTENT:
{context}
JOB DESCRIPTION:
{job_description}
Analyze and return JSON only.
"""
)
chain = (
{
"context": retriever,
"job_description": RunnablePassthrough(),
}
| prompt
| RunnableLambda(lambda chat_prompt_value: hf_llm(chat_prompt_value.to_string()))
| StrOutputParser()
)
return chain
# =====================================================
# 3. MAIN FUNCTION FOR ANALYSIS
# =====================================================
def analyze_resume_against_job(job_description: str, retriever, llm_callable):
chain = build_analysis_chain(retriever, llm_callable)
return chain.invoke(job_description)
__all__ = [
"retriever",
"vectorstore",
"hf_llm",
"analyze_resume_against_job",
"build_analysis_chain"
]
# =====================================================
# 4. Example test run
# =====================================================
if __name__ == "__main__":
job_desc = "What is the user's machine learning experience?"
result = analyze_resume_against_job(
job_description=job_desc,
retriever=retriever,
llm_callable=hf_llm
)
print("=== ANALYSIS ===")
print(result)
|