File size: 6,835 Bytes
2dbd321 88afe45 2dbd321 88afe45 2dbd321 88afe45 2dbd321 88afe45 | 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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | # =========================
# IMPORTS
# =========================
import gradio as gr
import json
import os
from openai import OpenAI
# =========================
# CONFIGURATION
# =========================
GROQ_API_KEY = os.getenv("Groq_api") # β
Matches your Hugging Face secret name
if not GROQ_API_KEY:
raise ValueError("Please set Groq_api environment variable in Hugging Face Secrets")
client = OpenAI(
api_key=GROQ_API_KEY,
base_url="https://api.groq.com/openai/v1"
)
PROFILE_FILE = "user_profile.json"
# =========================
# SAFE PARSER
# =========================
def extract_text(response):
try:
return response.choices[0].message.content
except Exception as e:
return f"β οΈ Error generating response. Please try again."
# =========================
# SAVE PROFILE
# =========================
def save_profile(exp, proj, port):
try:
profile = {
"experience": exp.strip(),
"projects": [p.strip() for p in proj.split("\n") if p.strip()],
"portfolio": [p.strip() for p in port.split(",") if p.strip()]
}
with open(PROFILE_FILE, "w") as f:
json.dump(profile, f)
return "β
Profile saved successfully!"
except Exception as e:
return f"β Error saving profile: {str(e)}"
# =========================
# LOAD PROFILE
# =========================
def load_profile_ui():
if not os.path.exists(PROFILE_FILE):
return "", "", ""
try:
with open(PROFILE_FILE, "r") as f:
p = json.load(f)
return (
p.get("experience", ""),
"\n".join(p.get("projects", [])),
", ".join(p.get("portfolio", []))
)
except:
return "", "", ""
# =========================
# PROJECT MATCHING
# =========================
def get_relevant_projects(job, projects):
if not projects:
return "No projects available."
projects_text = "\n".join(projects)
try:
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{
"role": "user",
"content": f"""
Select 1-2 most relevant projects for this job. Only list the project names/descriptions, no extra text.
Job:
{job}
Projects:
{projects_text}
"""
}],
temperature=0.7,
max_tokens=500
)
return extract_text(response)
except Exception as e:
return "Error selecting projects"
# =========================
# GENERATE PROPOSAL
# =========================
def generate_proposal(job_description):
if not job_description or not job_description.strip():
return "β Please enter a job description."
try:
if not os.path.exists(PROFILE_FILE):
return "β Please save your profile first!"
with open(PROFILE_FILE, "r") as f:
profile = json.load(f)
exp = profile.get("experience", "")
projects = profile.get("projects", [])
portfolio = profile.get("portfolio", [])
# Smart project selection
relevant_projects = get_relevant_projects(job_description, projects)
portfolio_text = ", ".join(portfolio)
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{
"role": "user",
"content": f"""
You are a top-rated freelancer.
Write a HIGH-CONVERTING proposal.
Rules:
- Hook in first 2 lines
- Max 180 words
- Bullet points
- Human tone
- Mention relevant experience only
- Include portfolio links
- End with a question
Job:
{job_description}
Experience:
{exp}
Relevant Projects:
{relevant_projects}
Portfolio Links:
{portfolio_text}
"""
}],
temperature=0.7,
max_tokens=800
)
proposal = extract_text(response)
return proposal
except Exception as e:
return f"β Failed to generate proposal. Please try again."
# =========================
# GRADIO UI
# =========================
with gr.Blocks(title="AI Proposal Generator") as demo:
gr.Markdown("""
# π AI Proposal Generator
### Generate high-converting freelance proposals in seconds
""")
with gr.Tab("π€ Profile Setup"):
gr.Markdown("### Set up your profile once - reuse forever!")
exp = gr.Textbox(
label="Your Experience",
lines=3,
placeholder="e.g., 5+ years of full-stack development with Python, React, and AWS..."
)
proj = gr.Textbox(
label="Your Projects (one per line)",
lines=4,
placeholder="E-commerce platform with 10k+ monthly users\nAI-powered chatbot for customer service\nMobile app for fitness tracking"
)
port = gr.Textbox(
label="Portfolio Links (comma separated)",
lines=2,
placeholder="https://github.com/yourusername, https://yourportfolio.com, https://linkedin.com/in/yourprofile"
)
save_btn = gr.Button("πΎ Save Profile", variant="primary")
save_out = gr.Textbox(label="Status", interactive=False)
save_btn.click(save_profile, [exp, proj, port], save_out)
demo.load(load_profile_ui, outputs=[exp, proj, port])
gr.Markdown("""
---
### π‘ Tips for best results:
- Be specific about your experience and skills
- Include quantifiable achievements in projects
- Add live links to your best work
""")
with gr.Tab("π Generate Proposal"):
gr.Markdown("### Paste the job description to generate a custom proposal")
job = gr.Textbox(
label="Job Description",
lines=8,
placeholder="Paste the full job description here..."
)
btn = gr.Button("π Generate Proposal", variant="primary", size="lg")
output = gr.Textbox(
label="Your Proposal",
lines=12,
interactive=False,
placeholder="Your generated proposal will appear here..."
)
btn.click(generate_proposal, job, output)
gr.Markdown("""
---
### π How it works:
1. AI analyzes the job requirements
2. Matches your most relevant projects
3. Generates a personalized, high-converting proposal
4. Ready to copy, paste, and win clients!
""")
# =========================
# LAUNCH
# =========================
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
theme=gr.themes.Soft(), # β
Theme moved to launch() for Gradio 6.0 compatibility
ssr_mode=False # β
Disable SSR to avoid experimental warning
) |