nainhaider's picture
Update app.py
88afe45 verified
Raw
History Blame Contribute Delete
6.84 kB
# =========================
# 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
)