LALAa11 commited on
Commit
d4c397a
·
verified ·
1 Parent(s): 6506419

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +117 -0
app.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import requests
4
+ from huggingface_hub import InferenceClient
5
+
6
+ # Load Gemini API key from environment variable
7
+ GEMINI_API_KEY = os.getenv("GOOGLE_AI_API_KEY")
8
+ HF_API_KEY = os.getenv("HUGGINGFACE_API_KEY") # optional if private model
9
+
10
+ # Hugging Face Client (free model, no API key needed for public models)
11
+ hf_client = InferenceClient(model="HuggingFaceH4/zephyr-7b-beta")
12
+
13
+ def generate_with_huggingface(resume_text, job_desc):
14
+ prompt = f"""
15
+ You are an expert career assistant.
16
+ Resume:
17
+ {resume_text}
18
+
19
+ Job Description:
20
+ {job_desc}
21
+
22
+ Task:
23
+ 1. Create a customized resume version highlighting relevant skills and achievements.
24
+ 2. Write a professional cover letter tailored for this role.
25
+ """
26
+
27
+ response = hf_client.text_generation(
28
+ prompt,
29
+ max_new_tokens=800,
30
+ temperature=0.7,
31
+ )
32
+ return response
33
+
34
+
35
+ def call_gemini_api(resume_text, job_desc):
36
+ if not GEMINI_API_KEY:
37
+ return None # force fallback
38
+
39
+ prompt = f"""
40
+ You are an expert career assistant.
41
+ Resume:
42
+ {resume_text}
43
+
44
+ Job Description:
45
+ {job_desc}
46
+
47
+ Task:
48
+ 1. Create a customized resume version highlighting relevant skills and achievements.
49
+ 2. Write a professional cover letter tailored for this role.
50
+ """
51
+
52
+ url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
53
+ headers = {
54
+ "Content-Type": "application/json",
55
+ "X-goog-api-key": GEMINI_API_KEY,
56
+ }
57
+ data = {
58
+ "contents": [
59
+ {"parts": [{"text": prompt}]}
60
+ ]
61
+ }
62
+
63
+ try:
64
+ response = requests.post(url, headers=headers, json=data, timeout=30)
65
+ result = response.json()
66
+
67
+ if "candidates" in result:
68
+ output_text = result["candidates"][0]["content"]["parts"][0]["text"]
69
+ return output_text
70
+ else:
71
+ return None
72
+ except Exception:
73
+ return None
74
+
75
+
76
+ def generate_documents(resume_text, job_desc):
77
+ # Try Gemini first
78
+ gemini_output = call_gemini_api(resume_text, job_desc)
79
+
80
+ if gemini_output:
81
+ output_text = gemini_output
82
+ source = "✅ Google Gemini"
83
+ else:
84
+ output_text = generate_with_huggingface(resume_text, job_desc)
85
+ source = "⚠️ Gemini failed → Using Hugging Face LLM"
86
+
87
+ # Split Resume + Cover Letter
88
+ if "Cover Letter" in output_text:
89
+ parts = output_text.split("Cover Letter")
90
+ resume_out = parts[0].strip()
91
+ cover_letter_out = "Cover Letter" + parts[1].strip()
92
+ else:
93
+ resume_out = output_text
94
+ cover_letter_out = ""
95
+
96
+ return resume_out + f"\n\n(Source: {source})", cover_letter_out
97
+
98
+
99
+ # Gradio UI
100
+ with gr.Blocks(title="AI Resume & Cover Letter Generator") as demo:
101
+ gr.Markdown("# 📄 AI Resume & Cover Letter Generator")
102
+ gr.Markdown("Upload your resume or paste LinkedIn profile + Job description, and get customized documents.\
103
+ \n(Default: Gemini, fallback: Hugging Face LLM)")
104
+
105
+ with gr.Row():
106
+ resume_input = gr.Textbox(label="Paste Resume / LinkedIn profile", lines=10, placeholder="Paste your resume text here...")
107
+ job_input = gr.Textbox(label="Paste Job Description", lines=8, placeholder="Paste job description here...")
108
+
109
+ generate_btn = gr.Button("✨ Generate Resume & Cover Letter")
110
+
111
+ with gr.Row():
112
+ resume_output = gr.Textbox(label="Customized Resume", lines=15)
113
+ cover_output = gr.Textbox(label="Cover Letter", lines=15)
114
+
115
+ generate_btn.click(generate_documents, inputs=[resume_input, job_input], outputs=[resume_output, cover_output])
116
+
117
+ demo.launch()