|
|
import os |
|
|
import gradio as gr |
|
|
import requests |
|
|
from huggingface_hub import InferenceClient |
|
|
|
|
|
|
|
|
GEMINI_API_KEY = os.getenv("GOOGLE_AI_API_KEY") |
|
|
HF_API_KEY = os.getenv("HUGGINGFACE_API_KEY") |
|
|
|
|
|
|
|
|
hf_client = InferenceClient(model="HuggingFaceH4/zephyr-7b-beta") |
|
|
|
|
|
def generate_with_huggingface(resume_text, job_desc): |
|
|
prompt = f""" |
|
|
You are an expert career assistant. |
|
|
Resume: |
|
|
{resume_text} |
|
|
|
|
|
Job Description: |
|
|
{job_desc} |
|
|
|
|
|
Task: |
|
|
1. Create a customized resume version highlighting relevant skills and achievements. |
|
|
2. Write a professional cover letter tailored for this role. |
|
|
""" |
|
|
|
|
|
response = hf_client.text_generation( |
|
|
prompt, |
|
|
max_new_tokens=800, |
|
|
temperature=0.7, |
|
|
) |
|
|
return response |
|
|
|
|
|
|
|
|
def call_gemini_api(resume_text, job_desc): |
|
|
if not GEMINI_API_KEY: |
|
|
return None |
|
|
|
|
|
prompt = f""" |
|
|
You are an expert career assistant. |
|
|
Resume: |
|
|
{resume_text} |
|
|
|
|
|
Job Description: |
|
|
{job_desc} |
|
|
|
|
|
Task: |
|
|
1. Create a customized resume version highlighting relevant skills and achievements. |
|
|
2. Write a professional cover letter tailored for this role. |
|
|
""" |
|
|
|
|
|
url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent" |
|
|
headers = { |
|
|
"Content-Type": "application/json", |
|
|
"X-goog-api-key": GEMINI_API_KEY, |
|
|
} |
|
|
data = { |
|
|
"contents": [ |
|
|
{"parts": [{"text": prompt}]} |
|
|
] |
|
|
} |
|
|
|
|
|
try: |
|
|
response = requests.post(url, headers=headers, json=data, timeout=30) |
|
|
result = response.json() |
|
|
|
|
|
if "candidates" in result: |
|
|
output_text = result["candidates"][0]["content"]["parts"][0]["text"] |
|
|
return output_text |
|
|
else: |
|
|
return None |
|
|
except Exception: |
|
|
return None |
|
|
|
|
|
|
|
|
def generate_documents(resume_text, job_desc): |
|
|
|
|
|
gemini_output = call_gemini_api(resume_text, job_desc) |
|
|
|
|
|
if gemini_output: |
|
|
output_text = gemini_output |
|
|
source = "β
Google Gemini" |
|
|
else: |
|
|
output_text = generate_with_huggingface(resume_text, job_desc) |
|
|
source = "β οΈ Gemini failed β Using Hugging Face LLM" |
|
|
|
|
|
|
|
|
if "Cover Letter" in output_text: |
|
|
parts = output_text.split("Cover Letter") |
|
|
resume_out = parts[0].strip() |
|
|
cover_letter_out = "Cover Letter" + parts[1].strip() |
|
|
else: |
|
|
resume_out = output_text |
|
|
cover_letter_out = "" |
|
|
|
|
|
return resume_out + f"\n\n(Source: {source})", cover_letter_out |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(title="AI Resume & Cover Letter Generator") as demo: |
|
|
gr.Markdown("# π AI Resume & Cover Letter Generator") |
|
|
gr.Markdown("Upload your resume or paste LinkedIn profile + Job description, and get customized documents.\ |
|
|
\n(Default: Gemini, fallback: Hugging Face LLM)") |
|
|
|
|
|
with gr.Row(): |
|
|
resume_input = gr.Textbox(label="Paste Resume / LinkedIn profile", lines=10, placeholder="Paste your resume text here...") |
|
|
job_input = gr.Textbox(label="Paste Job Description", lines=8, placeholder="Paste job description here...") |
|
|
|
|
|
generate_btn = gr.Button("β¨ Generate Resume & Cover Letter") |
|
|
|
|
|
with gr.Row(): |
|
|
resume_output = gr.Textbox(label="Customized Resume", lines=15) |
|
|
cover_output = gr.Textbox(label="Cover Letter", lines=15) |
|
|
|
|
|
generate_btn.click(generate_documents, inputs=[resume_input, job_input], outputs=[resume_output, cover_output]) |
|
|
|
|
|
demo.launch() |
|
|
|