Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| import numpy as np | |
| import faiss | |
| from sentence_transformers import SentenceTransformer | |
| from groq import Groq | |
| # ---------------- CONFIG ---------------- | |
| GROQ_API_KEY = os.getenv("GROQ_API_KEY") | |
| if not GROQ_API_KEY: | |
| raise ValueError("Please set GROQ_API_KEY in Hugging Face Secrets") | |
| # ---------------- INIT ---------------- | |
| client = Groq(api_key=GROQ_API_KEY) | |
| embedder = SentenceTransformer("all-MiniLM-L6-v2") | |
| EMBED_DIM = 384 | |
| faiss_index = faiss.IndexFlatIP(EMBED_DIM) | |
| candidates = [] | |
| # ---------------- HELPERS ---------------- | |
| def embed_text(text: str): | |
| vec = embedder.encode([text]) | |
| vec = vec / np.linalg.norm(vec) | |
| return vec.astype("float32") | |
| def llm_generate(prompt: str): | |
| completion = client.chat.completions.create( | |
| model="llama-3.1-8b-instant", | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.3 | |
| ) | |
| return completion.choices[0].message.content | |
| # ---------------- CORE FEATURES ---------------- | |
| def add_candidate(name, skills, experience): | |
| if not name or not skills: | |
| return ( | |
| "⚠️ Please fill in required fields.", | |
| gr.update(), | |
| gr.update(), | |
| gr.update() | |
| ) | |
| profile = f"Name: {name}\nSkills: {skills}\nExperience: {experience}" | |
| vec = embed_text(profile) | |
| faiss_index.add(vec) | |
| candidates.append(profile) | |
| return ( | |
| f"✅ Candidate **{name}** added successfully.", | |
| gr.update(value=""), # clear name | |
| gr.update(value=""), # clear skills | |
| gr.update(value="") # clear experience | |
| ) | |
| def generate_bio(raw_data): | |
| prompt = f""" | |
| You are a professional HR recruiter. | |
| Write a concise, formal candidate bio. | |
| Rules: | |
| - Professional tone | |
| - No emojis | |
| - No exaggeration | |
| - Max 120 words | |
| Candidate Data: | |
| {raw_data} | |
| """ | |
| return llm_generate(prompt) | |
| def rewrite_job(job_desc): | |
| prompt = f""" | |
| Rewrite the job description below to meet modern recruitment standards. | |
| Make it inclusive, clear, and well-structured. | |
| Job Description: | |
| {job_desc} | |
| """ | |
| return llm_generate(prompt) | |
| def recommend_candidates(job_query): | |
| if not candidates: | |
| return "No candidates available.", "", "⚠️ Add candidates first." | |
| job_vec = embed_text(job_query) | |
| scores, ids = faiss_index.search(job_vec, k=min(3, len(candidates))) | |
| ranked, reasons = [], [] | |
| for i, idx in enumerate(ids[0]): | |
| candidate = candidates[idx] | |
| explain_prompt = f""" | |
| Explain why this candidate matches the job. | |
| Focus only on skills and experience. | |
| Candidate: | |
| {candidate} | |
| Job Requirements: | |
| {job_query} | |
| """ | |
| ranked.append(f"### Rank {i+1}\n{candidate}") | |
| reasons.append(llm_generate(explain_prompt)) | |
| return "\n\n".join(ranked), "\n\n".join(reasons), "✅ Recommendations generated" | |
| # ---------------- LINKEDIN POST GENERATOR (NEW) ---------------- | |
| def generate_linkedin_post(context_type, content): | |
| prompt = f""" | |
| You are a LinkedIn content strategist for HR & AI professionals. | |
| Create a LinkedIn post based on the context below. | |
| Context Type: {context_type} | |
| Rules: | |
| - Professional but engaging tone | |
| - Short paragraphs | |
| - Strong hook at the beginning | |
| - Clear CTA at the end | |
| - 5–8 relevant hashtags | |
| - Max 2 emojis | |
| - Do NOT mention AI model names | |
| Content: | |
| {content} | |
| """ | |
| return llm_generate(prompt) | |
| # ---------------- UI ---------------- | |
| theme = gr.themes.Soft( | |
| primary_hue="blue", | |
| secondary_hue="slate", | |
| neutral_hue="gray", | |
| ) | |
| with gr.Blocks(theme=theme) as demo: | |
| gr.Markdown(""" | |
| # 🤖 AI Recruitment Assistant | |
| **Recruit smarter. Hire faster. Share better.** | |
| """) | |
| gr.Markdown("---") | |
| with gr.Tabs(): | |
| # -------- Add Candidate -------- | |
| with gr.Tab("➕ Add Candidate"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| name = gr.Textbox(label="Candidate Name *") | |
| skills = gr.Textbox(label="Key Skills *") | |
| experience = gr.Textbox(label="Experience Summary", lines=4) | |
| add_btn = gr.Button("Add Candidate", variant="primary") | |
| status = gr.Markdown() | |
| with gr.Column(): | |
| gr.Markdown(""" | |
| ### Tips | |
| - Mention years of experience | |
| - Use clear skill names | |
| - Avoid generic wording | |
| """) | |
| add_btn.click( | |
| add_candidate, | |
| inputs=[name, skills, experience], | |
| outputs=[status, name, skills, experience] | |
| ) | |
| # -------- Bio Generator -------- | |
| with gr.Tab("🧾 Candidate Bio Generator"): | |
| raw_data = gr.Textbox(lines=6, placeholder="Paste raw CV or notes...") | |
| bio_btn = gr.Button("Generate Bio", variant="primary") | |
| bio_output = gr.Textbox(lines=6) | |
| bio_btn.click(generate_bio, raw_data, bio_output) | |
| # -------- Job Rewriter -------- | |
| with gr.Tab("📄 Job Description Optimizer"): | |
| job_desc = gr.Textbox(lines=6, placeholder="Paste job description...") | |
| rewrite_btn = gr.Button("Rewrite Professionally", variant="primary") | |
| rewrite_output = gr.Textbox(lines=6) | |
| rewrite_btn.click(rewrite_job, job_desc, rewrite_output) | |
| # -------- Recommendation -------- | |
| with gr.Tab("🎯 Candidate Recommendation"): | |
| job_query = gr.Textbox(lines=5, placeholder="Enter job requirements...") | |
| rec_btn = gr.Button("Find Best Matches", variant="primary") | |
| with gr.Row(): | |
| rec_candidates = gr.Markdown() | |
| rec_explanation = gr.Textbox(lines=10) | |
| rec_status = gr.Markdown() | |
| rec_btn.click( | |
| recommend_candidates, | |
| job_query, | |
| [rec_candidates, rec_explanation, rec_status] | |
| ) | |
| # -------- LinkedIn Post Generator (NEW) -------- | |
| with gr.Tab("📣 LinkedIn Post Generator"): | |
| gr.Markdown("### Turn AI outputs into LinkedIn-ready posts") | |
| post_type = gr.Dropdown( | |
| label="Post Context", | |
| choices=[ | |
| "Candidate Bio Highlight", | |
| "Job Hiring Announcement", | |
| "AI-Based Candidate Recommendation" | |
| ] | |
| ) | |
| post_input = gr.Textbox( | |
| lines=8, | |
| placeholder="Paste generated bio, job description, or recommendation..." | |
| ) | |
| post_btn = gr.Button("Generate LinkedIn Post", variant="primary") | |
| post_output = gr.Textbox(lines=10, label="LinkedIn Post") | |
| post_btn.click( | |
| generate_linkedin_post, | |
| inputs=[post_type, post_input], | |
| outputs=post_output | |
| ) | |
| # -------- About -------- | |
| with gr.Tab("📘 About"): | |
| gr.Markdown(""" | |
| ### What is this app? | |
| An AI-powered recruitment assistant that helps recruiters: | |
| - Manage candidates | |
| - Improve hiring content | |
| - Match talent intelligently | |
| - Generate social media content | |
| ### Use Case | |
| Generate → Optimize → Match → Share on LinkedIn | |
| ### Ideal for | |
| Recruiters • HR Tech • AI Portfolios • Startups | |
| """) | |
| gr.Markdown("--- Built for Hugging Face Spaces 🚀") | |
| demo.launch() | |