File size: 3,642 Bytes
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
import os
import gradio as gr
import requests
from huggingface_hub import InferenceClient

# Load Gemini API key from environment variable
GEMINI_API_KEY = os.getenv("GOOGLE_AI_API_KEY")
HF_API_KEY = os.getenv("HUGGINGFACE_API_KEY")  # optional if private model

# Hugging Face Client (free model, no API key needed for public models)
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  # force fallback

    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):
    # Try Gemini first
    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


# Gradio UI
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()