File size: 4,806 Bytes
d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a 1626c71 d4c397a |
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 134 135 136 137 138 139 140 141 142 143 144 145 146 |
import os
import gradio as gr
import requests
from huggingface_hub import InferenceClient
# π Load API keys from environment
GEMINI_API_KEY = os.getenv("GOOGLE_AI_API_KEY")
HF_API_KEY = os.getenv("HUGGINGFACE_API_KEY") # optional for private HF models
# Hugging Face Client (public model as fallback)
hf_client = InferenceClient(model="HuggingFaceH4/zephyr-7b-beta")
# ========== AI Functions ==========
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"
# Split Resume + Cover Letter
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 ==========
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);}
}
"""
# ========== Gradio UI ==========
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()
|