# ========================= # 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 )