|
|
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: |
|
|
return result["candidates"][0]["content"]["parts"][0]["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 |
|
|
|
|
|
|
|
|
|
|
|
custom_css = """ |
|
|
body { |
|
|
background: linear-gradient(-45deg, #ff9a9e, #fad0c4, #a1c4fd, #c2e9fb); |
|
|
background-size: 400% 400%; |
|
|
animation: gradientBG 12s ease infinite; |
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
|
} |
|
|
@keyframes gradientBG { |
|
|
0% {background-position: 0% 50%;} |
|
|
50% {background-position: 100% 50%;} |
|
|
100% {background-position: 0% 50%;} |
|
|
} |
|
|
.gradio-container { |
|
|
animation: fadeIn 1.2s ease-in-out; |
|
|
} |
|
|
textarea, input { |
|
|
border-radius: 14px !important; |
|
|
box-shadow: 0px 4px 10px rgba(0,0,0,0.2) !important; |
|
|
padding: 10px !important; |
|
|
} |
|
|
button { |
|
|
background: linear-gradient(90deg, #667eea, #764ba2) !important; |
|
|
color: white !important; |
|
|
font-weight: bold !important; |
|
|
border-radius: 25px !important; |
|
|
transition: all 0.3s ease-in-out; |
|
|
padding: 12px 20px !important; |
|
|
} |
|
|
button:hover { |
|
|
transform: scale(1.07); |
|
|
box-shadow: 0px 6px 15px rgba(0,0,0,0.3); |
|
|
} |
|
|
@keyframes fadeIn { |
|
|
from {opacity: 0; transform: translateY(25px);} |
|
|
to {opacity: 1; transform: translateY(0);} |
|
|
} |
|
|
""" |
|
|
|
|
|
|
|
|
with gr.Blocks(css=custom_css, title="AI Resume & Cover Letter Generator") as demo: |
|
|
gr.Markdown("<h1 style='text-align:center; color:white;'>π AI Resume & Cover Letter Generator</h1>") |
|
|
gr.Markdown("<p style='text-align:center; color:white; font-size:18px;'>Paste your Resume + Job Description β Get a Customized Resume & Cover Letter</p>") |
|
|
|
|
|
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.Tabs(): |
|
|
with gr.Tab("π― Customized Resume"): |
|
|
resume_output = gr.Textbox(label="Customized Resume", lines=20) |
|
|
with gr.Tab("βοΈ Cover Letter"): |
|
|
cover_output = gr.Textbox(label="Cover Letter", lines=20) |
|
|
|
|
|
generate_btn.click(generate_documents, inputs=[resume_input, job_input], outputs=[resume_output, cover_output]) |
|
|
|
|
|
demo.launch() |
|
|
|