| |
| |
| |
| import gradio as gr |
| import json |
| import os |
| from openai import OpenAI |
|
|
| |
| |
| |
| GROQ_API_KEY = os.getenv("Groq_api") |
|
|
| 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" |
|
|
| |
| |
| |
| def extract_text(response): |
| try: |
| return response.choices[0].message.content |
| except Exception as e: |
| return f"β οΈ Error generating response. Please try again." |
|
|
| |
| |
| |
| 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)}" |
|
|
| |
| |
| |
| 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 "", "", "" |
|
|
| |
| |
| |
| 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" |
|
|
| |
| |
| |
| 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", []) |
|
|
| |
| 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." |
|
|
| |
| |
| |
| 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! |
| """) |
|
|
| |
| |
| |
| if __name__ == "__main__": |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| theme=gr.themes.Soft(), |
| ssr_mode=False |
| ) |