Spaces:
Sleeping
Sleeping
| """ | |
| Vero Template Generator Backend | |
| Flask API for generating professional documents using Gemini AI | |
| """ | |
| import io | |
| import os | |
| import sys | |
| from datetime import datetime | |
| from flask import Flask, jsonify, request, send_file | |
| from flask_cors import CORS | |
| from utils.docx_generator import get_docx_generator | |
| from utils.gemini_client import get_gemini_client | |
| from utils.pdf_generator import get_pdf_generator | |
| # Initialize Flask app | |
| app = Flask(__name__) | |
| CORS(app) | |
| # Initialize services | |
| try: | |
| gemini_client = get_gemini_client() | |
| docx_generator = get_docx_generator() | |
| pdf_generator = get_pdf_generator() | |
| print("✓ All services initialized successfully", file=sys.stderr) | |
| except Exception as e: | |
| print(f"✗ Error initializing services: {str(e)}", file=sys.stderr) | |
| sys.exit(1) | |
| # ============================================================================ | |
| # HEALTH CHECK | |
| # ============================================================================ | |
| def health_check(): | |
| """Health check endpoint""" | |
| return jsonify( | |
| { | |
| "status": "healthy", | |
| "service": "Vero Template Generator", | |
| "version": "1.0.0", | |
| "timestamp": datetime.now().isoformat(), | |
| "endpoints": [ | |
| "/generate-resume", | |
| "/generate-cover-letter", | |
| "/generate-proposal", | |
| "/generate-invoice", | |
| "/generate-contract", | |
| "/generate-portfolio-pdf", | |
| "/enhance-description", | |
| "/enhance-skills-summary", | |
| ], | |
| } | |
| ) | |
| # ============================================================================ | |
| # RESUME GENERATOR | |
| # ============================================================================ | |
| def generate_resume(): | |
| """ | |
| Generate professional resume | |
| Expected JSON: | |
| { | |
| "personal_info": { | |
| "name": "John Doe", | |
| "email": "john@example.com", | |
| "phone": "+1234567890", | |
| "location": "City, State", | |
| "linkedin": "linkedin.com/in/johndoe", | |
| "website": "johndoe.com" | |
| }, | |
| "summary": "Professional summary text", | |
| "experience": [ | |
| { | |
| "title": "Senior Developer", | |
| "company": "Tech Corp", | |
| "location": "City, State", | |
| "start_date": "Jan 2020", | |
| "end_date": "Present", | |
| "responsibilities": ["Task 1", "Task 2"] | |
| } | |
| ], | |
| "education": [ | |
| { | |
| "degree": "Bachelor of Science", | |
| "field": "Computer Science", | |
| "school": "University Name", | |
| "graduation_date": "May 2019", | |
| "gpa": "3.8", | |
| "honors": "Magna Cum Laude" | |
| } | |
| ], | |
| "skills": ["Python", "JavaScript", "React"], | |
| "certifications": [ | |
| { | |
| "name": "AWS Certified", | |
| "issuer": "Amazon", | |
| "date": "2023" | |
| } | |
| ], | |
| "projects": [ | |
| { | |
| "name": "Project Name", | |
| "description": "Description", | |
| "technologies": ["Tech1", "Tech2"] | |
| } | |
| ], | |
| "enhance_with_ai": true | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| # Optional: Enhance descriptions with AI | |
| if data.get("enhance_with_ai", False): | |
| print("Enhancing resume content with AI...", file=sys.stderr) | |
| # Enhance professional summary | |
| if data.get("summary"): | |
| skills = data.get("skills", []) | |
| if isinstance(skills, dict): | |
| skills = [s for skill_list in skills.values() for s in skill_list] | |
| data["summary"] = gemini_client.generate_skills_summary( | |
| skills, data.get("years_experience", 0) | |
| ) | |
| # Enhance work experience descriptions | |
| if data.get("experience"): | |
| for exp in data["experience"]: | |
| if exp.get("responsibilities"): | |
| enhanced_resps = [] | |
| for resp in exp["responsibilities"]: | |
| try: | |
| enhanced = gemini_client.enhance_resume_description( | |
| resp, exp.get("title", "") | |
| ) | |
| enhanced_resps.append(enhanced) | |
| except Exception as e: | |
| print( | |
| f"Error enhancing responsibility: {str(e)}", | |
| file=sys.stderr, | |
| ) | |
| enhanced_resps.append(resp) | |
| exp["responsibilities"] = enhanced_resps | |
| # Enhance project descriptions | |
| if data.get("projects"): | |
| for proj in data["projects"]: | |
| if proj.get("description"): | |
| try: | |
| enhanced = gemini_client.enhance_portfolio_description(proj) | |
| proj["description"] = enhanced | |
| except Exception as e: | |
| print(f"Error enhancing project: {str(e)}", file=sys.stderr) | |
| # Generate DOCX | |
| print("Generating resume document...", file=sys.stderr) | |
| docx_buffer = docx_generator.generate_resume(data) | |
| # Prepare filename | |
| name = data.get("personal_info", {}).get("name", "Resume") | |
| filename = f"{name.replace(' ', '_')}_Resume.docx" | |
| return send_file( | |
| docx_buffer, | |
| mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| as_attachment=True, | |
| download_name=filename, | |
| ) | |
| except Exception as e: | |
| print(f"Error generating resume: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| # ============================================================================ | |
| # COVER LETTER GENERATOR | |
| # ============================================================================ | |
| def generate_cover_letter(): | |
| """ | |
| Generate personalized cover letter | |
| Expected JSON: | |
| { | |
| "name": "John Doe", | |
| "address": "123 Main St, City, State", | |
| "email": "john@example.com", | |
| "phone": "+1234567890", | |
| "date": "January 15, 2024", | |
| "company": "Tech Corp", | |
| "hiring_manager": "Jane Smith", | |
| "position": "Senior Developer", | |
| "skills": ["Python", "React", "AWS"], | |
| "experience": "5 years of full-stack development", | |
| "tone": "formal", | |
| "custom_content": "Optional pre-written content", | |
| "generate_with_ai": true | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| # Generate content with AI if requested | |
| if data.get("generate_with_ai", True) and not data.get("custom_content"): | |
| print("Generating cover letter content with AI...", file=sys.stderr) | |
| content = gemini_client.generate_cover_letter(data) | |
| data["content"] = content | |
| elif data.get("custom_content"): | |
| data["content"] = data["custom_content"] | |
| else: | |
| return ( | |
| jsonify( | |
| { | |
| "error": "Either generate_with_ai must be true or custom_content must be provided" | |
| } | |
| ), | |
| 400, | |
| ) | |
| # Generate DOCX | |
| print("Generating cover letter document...", file=sys.stderr) | |
| docx_buffer = docx_generator.generate_cover_letter(data) | |
| # Prepare filename | |
| name = data.get("name", "Applicant").replace(" ", "_") | |
| company = data.get("company", "Company").replace(" ", "_") | |
| filename = f"{name}_CoverLetter_{company}.docx" | |
| return send_file( | |
| docx_buffer, | |
| mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| as_attachment=True, | |
| download_name=filename, | |
| ) | |
| except Exception as e: | |
| print(f"Error generating cover letter: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| # ============================================================================ | |
| # PROPOSAL GENERATOR | |
| # ============================================================================ | |
| def generate_proposal(): | |
| """ | |
| Generate business proposal | |
| Expected JSON: | |
| { | |
| "title": "Web Development Proposal", | |
| "client_name": "ABC Company", | |
| "prepared_by": "Your Company Name", | |
| "date": "January 15, 2024", | |
| "project_title": "E-commerce Website", | |
| "scope": "Develop a full-featured e-commerce platform", | |
| "deliverables": ["Website", "Admin Panel", "Mobile App"], | |
| "timeline": "3 months", | |
| "budget": "$50,000", | |
| "generate_with_ai": true, | |
| "custom_content": "Optional pre-written proposal" | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| # Generate proposal content with AI if requested | |
| if data.get("generate_with_ai", True) and not data.get("custom_content"): | |
| print("Generating proposal content with AI...", file=sys.stderr) | |
| content = gemini_client.generate_proposal(data) | |
| data["content"] = content | |
| elif data.get("custom_content"): | |
| data["content"] = data["custom_content"] | |
| # Generate DOCX | |
| print("Generating proposal document...", file=sys.stderr) | |
| docx_buffer = docx_generator.generate_proposal(data) | |
| # Prepare filename | |
| client = data.get("client_name", "Client").replace(" ", "_") | |
| title = data.get("project_title", "Proposal").replace(" ", "_") | |
| filename = f"Proposal_{client}_{title}.docx" | |
| return send_file( | |
| docx_buffer, | |
| mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| as_attachment=True, | |
| download_name=filename, | |
| ) | |
| except Exception as e: | |
| print(f"Error generating proposal: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| # ============================================================================ | |
| # INVOICE GENERATOR | |
| # ============================================================================ | |
| def generate_invoice(): | |
| """ | |
| Generate professional invoice | |
| Expected JSON: | |
| { | |
| "invoice_number": "INV-001", | |
| "invoice_date": "2024-01-15", | |
| "due_date": "2024-02-15", | |
| "from_info": { | |
| "name": "Your Business", | |
| "address": "123 Business St", | |
| "email": "billing@business.com", | |
| "phone": "+1234567890" | |
| }, | |
| "to_info": { | |
| "name": "Client Name", | |
| "address": "456 Client Ave", | |
| "email": "client@example.com" | |
| }, | |
| "items": [ | |
| { | |
| "description": "Service/Product", | |
| "quantity": 1, | |
| "rate": 1000, | |
| "amount": 1000 | |
| } | |
| ], | |
| "tax_rate": 8.5, | |
| "discount": 0, | |
| "notes": "Thank you for your business", | |
| "payment_instructions": "Payment via bank transfer" | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| # Validate required fields | |
| if not data.get("items"): | |
| return jsonify({"error": "Invoice items are required"}), 400 | |
| # Generate DOCX | |
| print("Generating invoice document...", file=sys.stderr) | |
| docx_buffer = docx_generator.generate_invoice(data) | |
| # Prepare filename | |
| invoice_num = data.get("invoice_number", "INV-001").replace("/", "-") | |
| filename = f"Invoice_{invoice_num}.docx" | |
| return send_file( | |
| docx_buffer, | |
| mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| as_attachment=True, | |
| download_name=filename, | |
| ) | |
| except Exception as e: | |
| print(f"Error generating invoice: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| # ============================================================================ | |
| # CONTRACT GENERATOR | |
| # ============================================================================ | |
| def generate_contract(): | |
| """ | |
| Generate legal contract | |
| Expected JSON: | |
| { | |
| "contract_type": "Freelance Service Agreement", | |
| "date": "January 15, 2024", | |
| "party1": { | |
| "name": "Service Provider", | |
| "address": "123 Provider St" | |
| }, | |
| "party2": { | |
| "name": "Client Name", | |
| "address": "456 Client Ave" | |
| }, | |
| "effective_date": "January 20, 2024", | |
| "expiration_date": "December 31, 2024", | |
| "custom_terms": "Net 30 payment terms", | |
| "generate_with_ai": true, | |
| "custom_content": "Optional pre-written terms" | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| # Generate contract terms with AI if requested | |
| if data.get("generate_with_ai", True) and not data.get("custom_content"): | |
| print("Generating contract terms with AI...", file=sys.stderr) | |
| contract_type = data.get("contract_type", "Service Agreement") | |
| custom_terms = data.get("custom_terms", "") | |
| terms = gemini_client.enhance_contract_terms(contract_type, custom_terms) | |
| data["terms"] = terms | |
| elif data.get("custom_content"): | |
| data["terms"] = data["custom_content"] | |
| # Generate DOCX | |
| print("Generating contract document...", file=sys.stderr) | |
| docx_buffer = docx_generator.generate_contract(data) | |
| # Prepare filename | |
| contract_type = data.get("contract_type", "Contract").replace(" ", "_") | |
| filename = f"{contract_type}_Contract.docx" | |
| return send_file( | |
| docx_buffer, | |
| mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| as_attachment=True, | |
| download_name=filename, | |
| ) | |
| except Exception as e: | |
| print(f"Error generating contract: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| # ============================================================================ | |
| # PORTFOLIO PDF EXPORT | |
| # ============================================================================ | |
| def generate_portfolio_pdf(): | |
| """ | |
| Generate portfolio PDF | |
| Expected JSON: | |
| { | |
| "name": "John Doe", | |
| "title": "Full Stack Developer", | |
| "bio": "Professional bio text", | |
| "contact": { | |
| "email": "john@example.com", | |
| "phone": "+1234567890", | |
| "website": "johndoe.com", | |
| "linkedin": "linkedin.com/in/johndoe" | |
| }, | |
| "skills": ["Python", "React", "AWS"], | |
| "experience": [...], | |
| "education": [...], | |
| "projects": [...], | |
| "certifications": [...], | |
| "enhance_with_ai": false | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| # Optional AI enhancement | |
| if data.get("enhance_with_ai", False): | |
| print("Enhancing portfolio content with AI...", file=sys.stderr) | |
| # Enhance bio | |
| if data.get("bio"): | |
| data["bio"] = gemini_client.improve_text_quality( | |
| data["bio"], "professional" | |
| ) | |
| # Enhance project descriptions | |
| if data.get("projects"): | |
| for proj in data["projects"]: | |
| if proj.get("description"): | |
| try: | |
| enhanced = gemini_client.enhance_portfolio_description(proj) | |
| proj["description"] = enhanced | |
| except Exception as e: | |
| print(f"Error enhancing project: {str(e)}", file=sys.stderr) | |
| # Generate PDF | |
| print("Generating portfolio PDF...", file=sys.stderr) | |
| pdf_buffer = pdf_generator.generate_portfolio_pdf(data) | |
| # Prepare filename | |
| name = data.get("name", "Portfolio").replace(" ", "_") | |
| filename = f"{name}_Portfolio.pdf" | |
| return send_file( | |
| pdf_buffer, | |
| mimetype="application/pdf", | |
| as_attachment=True, | |
| download_name=filename, | |
| ) | |
| except Exception as e: | |
| print(f"Error generating portfolio PDF: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| # ============================================================================ | |
| # AI ENHANCEMENT UTILITIES | |
| # ============================================================================ | |
| def enhance_description(): | |
| """ | |
| Enhance text description with AI | |
| Expected JSON: | |
| { | |
| "text": "Original text to enhance", | |
| "context": "resume/portfolio/proposal", | |
| "role": "Optional job role for context" | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data or not data.get("text"): | |
| return jsonify({"error": "Text is required"}), 400 | |
| text = data["text"] | |
| context = data.get("context", "general") | |
| role = data.get("role", "") | |
| if context == "resume": | |
| enhanced = gemini_client.enhance_resume_description(text, role) | |
| elif context == "portfolio": | |
| project_data = { | |
| "title": role, | |
| "description": text, | |
| "technologies": data.get("technologies", []), | |
| "role": data.get("your_role", "Developer"), | |
| } | |
| enhanced = gemini_client.enhance_portfolio_description(project_data) | |
| else: | |
| enhanced = gemini_client.improve_text_quality(text, "professional") | |
| return jsonify({"original": text, "enhanced": enhanced, "success": True}) | |
| except Exception as e: | |
| print(f"Error enhancing description: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| def enhance_skills_summary(): | |
| """ | |
| Generate professional skills summary | |
| Expected JSON: | |
| { | |
| "skills": ["Python", "React", "AWS"], | |
| "experience_years": 5 | |
| } | |
| """ | |
| try: | |
| data = request.get_json() | |
| if not data or not data.get("skills"): | |
| return jsonify({"error": "Skills list is required"}), 400 | |
| skills = data["skills"] | |
| years = data.get("experience_years", 0) | |
| summary = gemini_client.generate_skills_summary(skills, years) | |
| return jsonify({"skills": skills, "summary": summary, "success": True}) | |
| except Exception as e: | |
| print(f"Error generating skills summary: {str(e)}", file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| def index(): | |
| return jsonify({ | |
| "service": "Vero Template Generator", | |
| "message": "API is running", | |
| "health": "/health" | |
| }) | |
| # ============================================================================ | |
| # ERROR HANDLERS | |
| # ============================================================================ | |
| def not_found(error): | |
| """Handle 404 errors""" | |
| return jsonify({"error": "Endpoint not found"}), 404 | |
| def internal_error(error): | |
| """Handle 500 errors""" | |
| return jsonify({"error": "Internal server error"}), 500 | |
| # ============================================================================ | |
| # MAIN | |
| # ============================================================================ | |
| if __name__ == "__main__": | |
| port = int(os.environ.get("PORT", 7860)) | |
| app.run(host="0.0.0.0", port=port, debug=False) | |