Muhammad-Izhan commited on
Commit
50fb52f
·
verified ·
1 Parent(s): ff684d6

Upload 8 files

Browse files
Files changed (8) hide show
  1. .env +1 -0
  2. Dockerfile +20 -0
  3. README.md +33 -10
  4. app.py +131 -0
  5. requirements.txt +5 -0
  6. static/css/style.css +182 -0
  7. static/js/script.js +181 -0
  8. templates/index.html +89 -0
.env ADDED
@@ -0,0 +1 @@
 
 
1
+ OPENROUTER_API_KEY=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
Dockerfile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+
3
+ # Install dependencies for wkhtmltopdf
4
+ RUN apt-get update && apt-get install -y \
5
+ wkhtmltopdf \
6
+ build-essential \
7
+ libssl-dev \
8
+ libffi-dev \
9
+ python3-dev \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ WORKDIR /app
13
+ COPY . /app/
14
+
15
+ RUN pip install --upgrade pip
16
+ RUN pip install -r requirements.txt
17
+
18
+ EXPOSE 7860
19
+
20
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -1,10 +1,33 @@
1
- ---
2
- title: AI Resume Builder
3
- emoji: 🏢
4
- colorFrom: indigo
5
- colorTo: indigo
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AI-Powered Resume Builder
2
+
3
+ A smart resume builder that uses AI to analyze and improve your resume for better ATS compatibility and hiring potential.
4
+
5
+ ## Features
6
+
7
+ - Drag-and-drop resume sections
8
+ - AI-powered suggestions for improvement
9
+ - ATS-friendly resume generation
10
+ - PDF export functionality
11
+
12
+ ## Technologies Used
13
+
14
+ - Frontend: HTML5, CSS3, JavaScript
15
+ - Backend: Python (Flask)
16
+ - AI: OpenAI GPT-3.5 API
17
+ - PDF Generation: pdfkit/wkhtmltopdf
18
+
19
+ ## Setup Instructions
20
+
21
+ 1. Clone the repository
22
+ 2. Install Python dependencies: `pip install -r requirements.txt`
23
+ 3. Set up your OpenAI API key in a `.env` file
24
+ 4. Run the application: `python app.py`
25
+ 5. Access the app at `http://localhost:5000`
26
+
27
+ ## Deployment
28
+
29
+ This app can be deployed to:
30
+ - Heroku
31
+ - PythonAnywhere
32
+ - AWS Elastic Beanstalk
33
+ - Google App Engine
app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify
2
+ import os
3
+ from werkzeug.utils import secure_filename
4
+ import pdfkit
5
+ import requests
6
+ import json
7
+ from dotenv import load_dotenv
8
+
9
+ load_dotenv()
10
+
11
+ app = Flask(__name__)
12
+
13
+ UPLOAD_FOLDER = 'uploads'
14
+ ALLOWED_EXTENSIONS = {'pdf', 'doc', 'docx'}
15
+ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
16
+
17
+ # Linux-compatible wkhtmltopdf path for Hugging Face
18
+ wkhtmltopdf_path = '/usr/bin/wkhtmltopdf' # Use system path (you'll install this in Dockerfile)
19
+ config = pdfkit.configuration(wkhtmltopdf=wkhtmltopdf_path)
20
+
21
+ def allowed_file(filename):
22
+ return '.' in filename and \
23
+ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
24
+
25
+ @app.route('/')
26
+ def index():
27
+ return render_template('index.html')
28
+
29
+ @app.route('/analyze', methods=['POST'])
30
+ def analyze_resume():
31
+ data = request.json
32
+ resume_text = data.get('resume_text', '')
33
+
34
+ api_key = os.getenv('OPENROUTER_API_KEY')
35
+ if not api_key:
36
+ return jsonify({"success": False, "error": "API key not configured"})
37
+
38
+ headers = {
39
+ "Authorization": f"Bearer {api_key}",
40
+ "HTTP-Referer": "http://localhost:5000",
41
+ "X-Title": "AI Resume Builder"
42
+ }
43
+
44
+ payload = {
45
+ "model": "openai/gpt-3.5-turbo",
46
+ "messages": [
47
+ {"role": "system", "content": "You are a professional resume analyzer. Provide specific, actionable suggestions to improve this resume for ATS compatibility and hiring potential."},
48
+ {"role": "user", "content": f"Please analyze this resume and provide improvement suggestions:\n\n{resume_text}"}
49
+ ],
50
+ "temperature": 0.7
51
+ }
52
+
53
+ try:
54
+ response = requests.post(
55
+ "https://openrouter.ai/api/v1/chat/completions",
56
+ headers=headers,
57
+ json=payload,
58
+ timeout=30
59
+ )
60
+ response.raise_for_status()
61
+ suggestions = response.json()["choices"][0]["message"]["content"]
62
+ return jsonify({"success": True, "suggestions": suggestions})
63
+
64
+ except requests.exceptions.RequestException as e:
65
+ return jsonify({"success": False, "error": f"API request failed: {str(e)}"})
66
+ except Exception as e:
67
+ return jsonify({"success": False, "error": f"Unexpected error: {str(e)}"})
68
+
69
+ @app.route('/improve', methods=['POST'])
70
+ def improve_section():
71
+ data = request.json
72
+ section_text = data.get('section_text', '')
73
+ section_type = data.get('section_type', 'general')
74
+
75
+ api_key = os.getenv('OPENROUTER_API_KEY')
76
+ if not api_key:
77
+ return jsonify({"success": False, "error": "API key not configured"})
78
+
79
+ headers = {
80
+ "Authorization": f"Bearer {api_key}",
81
+ "HTTP-Referer": "http://localhost:5000",
82
+ "X-Title": "AI Resume Builder"
83
+ }
84
+
85
+ payload = {
86
+ "model": "qwen/qwq-32b:free",
87
+ "messages": [
88
+ {"role": "system", "content": f"You are a professional resume writer. Improve this {section_type} section to be more impactful and ATS-friendly."},
89
+ {"role": "user", "content": section_text}
90
+ ],
91
+ "temperature": 0.5
92
+ }
93
+
94
+ try:
95
+ response = requests.post(
96
+ "https://openrouter.ai/api/v1/chat/completions",
97
+ headers=headers,
98
+ json=payload,
99
+ timeout=30
100
+ )
101
+ response.raise_for_status()
102
+ improved_text = response.json()["choices"][0]["message"]["content"]
103
+ return jsonify({"success": True, "improved_text": improved_text})
104
+
105
+ except requests.exceptions.RequestException as e:
106
+ return jsonify({"success": False, "error": f"API request failed: {str(e)}"})
107
+ except Exception as e:
108
+ return jsonify({"success": False, "error": f"Unexpected error: {str(e)}"})
109
+
110
+ @app.route('/generate-pdf', methods=['POST'])
111
+ def generate_pdf():
112
+ data = request.json
113
+ html_content = data.get('html_content', '')
114
+
115
+ try:
116
+ pdf = pdfkit.from_string(html_content, False, configuration=config)
117
+ return jsonify({
118
+ "success": True,
119
+ "pdf": pdf.decode('latin-1')
120
+ })
121
+
122
+ except Exception as e:
123
+ return jsonify({"success": False, "error": f"PDF generation failed: {str(e)}. Please ensure wkhtmltopdf is installed at {wkhtmltopdf_path}"})
124
+
125
+
126
+ # Required for Hugging Face
127
+ if __name__ == "__main__":
128
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
129
+ app.run(debug=True, host="0.0.0.0", port=7860)
130
+ else:
131
+ server = app
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Flask==2.3.2
2
+ python-dotenv==1.0.0
3
+ pdfkit==1.0.0
4
+ wkhtmltopdf==0.2
5
+ requests==2.31.0
static/css/style.css ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --primary-color: #4361ee;
3
+ --secondary-color: #3f37c9;
4
+ --accent-color: #4895ef;
5
+ --light-color: #f8f9fa;
6
+ --dark-color: #212529;
7
+ --success-color: #4bb543;
8
+ }
9
+
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ font-family: 'Poppins', sans-serif;
15
+ }
16
+
17
+ body {
18
+ background-color: #f5f7fa;
19
+ color: var(--dark-color);
20
+ line-height: 1.6;
21
+ }
22
+
23
+ .container {
24
+ max-width: 1200px;
25
+ margin: 0 auto;
26
+ padding: 20px;
27
+ }
28
+
29
+ header {
30
+ text-align: center;
31
+ margin-bottom: 30px;
32
+ }
33
+
34
+ header h1 {
35
+ font-size: 2.5rem;
36
+ color: var(--primary-color);
37
+ margin-bottom: 10px;
38
+ }
39
+
40
+ header p {
41
+ font-size: 1.1rem;
42
+ color: #666;
43
+ }
44
+
45
+ .builder-container {
46
+ display: flex;
47
+ gap: 30px;
48
+ }
49
+
50
+ .resume-form, .resume-preview {
51
+ background: white;
52
+ border-radius: 10px;
53
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
54
+ padding: 25px;
55
+ flex: 1;
56
+ }
57
+
58
+ .resume-preview {
59
+ background: #f9f9f9;
60
+ }
61
+
62
+ h2 {
63
+ color: var(--primary-color);
64
+ margin-bottom: 20px;
65
+ padding-bottom: 10px;
66
+ border-bottom: 2px solid #eee;
67
+ }
68
+
69
+ .form-section {
70
+ margin-bottom: 25px;
71
+ padding: 20px;
72
+ border: 1px dashed #ddd;
73
+ border-radius: 8px;
74
+ background: #fafafa;
75
+ cursor: move;
76
+ }
77
+
78
+ .form-section:hover {
79
+ border-color: var(--accent-color);
80
+ }
81
+
82
+ .form-section h3 {
83
+ margin-bottom: 15px;
84
+ color: var(--secondary-color);
85
+ }
86
+
87
+ input, textarea {
88
+ width: 100%;
89
+ padding: 10px;
90
+ margin-bottom: 15px;
91
+ border: 1px solid #ddd;
92
+ border-radius: 4px;
93
+ font-size: 1rem;
94
+ }
95
+
96
+ textarea {
97
+ min-height: 100px;
98
+ resize: vertical;
99
+ }
100
+
101
+ button {
102
+ background-color: var(--primary-color);
103
+ color: white;
104
+ border: none;
105
+ padding: 10px 15px;
106
+ border-radius: 4px;
107
+ cursor: pointer;
108
+ font-size: 1rem;
109
+ transition: all 0.3s ease;
110
+ }
111
+
112
+ button:hover {
113
+ background-color: var(--secondary-color);
114
+ transform: translateY(-2px);
115
+ }
116
+
117
+ .ai-suggest {
118
+ background-color: var(--accent-color);
119
+ margin-top: 10px;
120
+ }
121
+
122
+ .actions {
123
+ display: flex;
124
+ gap: 10px;
125
+ margin-top: 20px;
126
+ }
127
+
128
+ #download-pdf {
129
+ background-color: var(--success-color);
130
+ }
131
+
132
+ #preview-resume {
133
+ background-color: #6c757d;
134
+ }
135
+
136
+ /* Drag and drop styling */
137
+ .form-section.dragging {
138
+ opacity: 0.5;
139
+ border: 2px dashed var(--accent-color);
140
+ }
141
+
142
+ /* Modal styles */
143
+ .modal {
144
+ display: none;
145
+ position: fixed;
146
+ z-index: 1;
147
+ left: 0;
148
+ top: 0;
149
+ width: 100%;
150
+ height: 100%;
151
+ overflow: auto;
152
+ background-color: rgba(0,0,0,0.4);
153
+ }
154
+
155
+ .modal-content {
156
+ background-color: #fefefe;
157
+ margin: 15% auto;
158
+ padding: 20px;
159
+ border-radius: 8px;
160
+ width: 80%;
161
+ max-width: 600px;
162
+ box-shadow: 0 5px 15px rgba(0,0,0,0.2);
163
+ }
164
+
165
+ .close {
166
+ color: #aaa;
167
+ float: right;
168
+ font-size: 28px;
169
+ font-weight: bold;
170
+ cursor: pointer;
171
+ }
172
+
173
+ .close:hover {
174
+ color: black;
175
+ }
176
+
177
+ /* Responsive design */
178
+ @media (max-width: 768px) {
179
+ .builder-container {
180
+ flex-direction: column;
181
+ }
182
+ }
static/js/script.js ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', function() {
2
+ // Drag and drop functionality
3
+ const sections = document.querySelectorAll('.form-section');
4
+ let draggedSection = null;
5
+
6
+ sections.forEach(section => {
7
+ section.addEventListener('dragstart', function() {
8
+ draggedSection = this;
9
+ setTimeout(() => {
10
+ this.classList.add('dragging');
11
+ }, 0);
12
+ });
13
+
14
+ section.addEventListener('dragend', function() {
15
+ this.classList.remove('dragging');
16
+ });
17
+ });
18
+
19
+ const form = document.querySelector('.resume-form');
20
+ form.addEventListener('dragover', function(e) {
21
+ e.preventDefault();
22
+ const afterElement = getDragAfterElement(form, e.clientY);
23
+ if (afterElement == null) {
24
+ form.appendChild(draggedSection);
25
+ } else {
26
+ form.insertBefore(draggedSection, afterElement);
27
+ }
28
+ });
29
+
30
+ function getDragAfterElement(container, y) {
31
+ const draggableElements = [...container.querySelectorAll('.form-section:not(.dragging)')];
32
+
33
+ return draggableElements.reduce((closest, child) => {
34
+ const box = child.getBoundingClientRect();
35
+ const offset = y - box.top - box.height / 2;
36
+ if (offset < 0 && offset > closest.offset) {
37
+ return { offset: offset, element: child };
38
+ } else {
39
+ return closest;
40
+ }
41
+ }, { offset: Number.NEGATIVE_INFINITY }).element;
42
+ }
43
+
44
+ // Add experience entry
45
+ document.getElementById('add-experience').addEventListener('click', function() {
46
+ const experienceSection = this.parentElement;
47
+ const newEntry = document.createElement('div');
48
+ newEntry.className = 'experience-entry';
49
+ newEntry.innerHTML = `
50
+ <input type="text" class="job-title" placeholder="Job Title">
51
+ <input type="text" class="company" placeholder="Company">
52
+ <input type="text" class="duration" placeholder="Duration">
53
+ <textarea class="description" placeholder="Job Description"></textarea>
54
+ <button class="ai-suggest" data-for="experience">Improve with AI</button>
55
+ `;
56
+ experienceSection.insertBefore(newEntry, this);
57
+ });
58
+
59
+ // Add skills
60
+ document.getElementById('add-skill').addEventListener('click', function() {
61
+ const skillInput = document.getElementById('skills-input');
62
+ const skillsList = document.getElementById('skills-list');
63
+
64
+ if (skillInput.value.trim() !== '') {
65
+ const skillTag = document.createElement('span');
66
+ skillTag.className = 'skill-tag';
67
+ skillTag.textContent = skillInput.value;
68
+ skillsList.appendChild(skillTag);
69
+ skillInput.value = '';
70
+ }
71
+ });
72
+
73
+ // AI Suggestions
74
+ const modal = document.getElementById('ai-modal');
75
+ const span = document.getElementsByClassName('close')[0];
76
+ const aiSuggestions = document.getElementById('ai-suggestions');
77
+ let currentField = '';
78
+
79
+ document.querySelectorAll('.ai-suggest').forEach(button => {
80
+ button.addEventListener('click', function() {
81
+ currentField = this.getAttribute('data-for');
82
+ const fieldContent = getFieldContent(currentField);
83
+
84
+ // In a real app, you would call your backend API here
85
+ // For now, we'll simulate a response
86
+ simulateAIResponse(fieldContent);
87
+
88
+ modal.style.display = 'block';
89
+ });
90
+ });
91
+
92
+ span.onclick = function() {
93
+ modal.style.display = 'none';
94
+ }
95
+
96
+ window.onclick = function(event) {
97
+ if (event.target == modal) {
98
+ modal.style.display = 'none';
99
+ }
100
+ }
101
+
102
+ document.getElementById('apply-suggestion').addEventListener('click', function() {
103
+ // In a real app, you would apply the selected suggestion
104
+ alert('Suggestion applied!');
105
+ modal.style.display = 'none';
106
+ });
107
+
108
+ function getFieldContent(field) {
109
+ switch(field) {
110
+ case 'summary':
111
+ return document.getElementById('summary').value;
112
+ case 'experience':
113
+ // Get the last experience entry's description
114
+ const experiences = document.querySelectorAll('.experience-entry');
115
+ const lastExperience = experiences[experiences.length - 1];
116
+ return lastExperience.querySelector('.description').value;
117
+ default:
118
+ return '';
119
+ }
120
+ }
121
+
122
+ function simulateAIResponse(content) {
123
+ // This is just a simulation - in a real app, you'd call the OpenAI API
124
+ const responses = {
125
+ summary: [
126
+ "Consider starting with a strong action word and quantifying your achievements.",
127
+ "Try to align your summary more closely with the job description keywords.",
128
+ "Your summary could benefit from more specific metrics about your impact."
129
+ ],
130
+ experience: [
131
+ "Reformat your bullet points to start with action verbs and include measurable results.",
132
+ "Consider adding more context about the scale of your projects or responsibilities.",
133
+ "This could be strengthened by showing progression or promotion if applicable."
134
+ ]
135
+ };
136
+
137
+ aiSuggestions.innerHTML = '';
138
+ responses[currentField].forEach((suggestion, index) => {
139
+ const suggestionDiv = document.createElement('div');
140
+ suggestionDiv.className = 'suggestion';
141
+ suggestionDiv.innerHTML = `
142
+ <input type="radio" id="suggestion-${index}" name="ai-suggestion" value="${index}">
143
+ <label for="suggestion-${index}">${suggestion}</label>
144
+ `;
145
+ aiSuggestions.appendChild(suggestionDiv);
146
+ });
147
+ }
148
+
149
+ // Preview Resume
150
+ document.getElementById('preview-resume').addEventListener('click', function() {
151
+ // In a real app, you would generate a proper preview
152
+ const previewContent = document.getElementById('preview-content');
153
+ previewContent.innerHTML = `
154
+ <h3>${document.getElementById('name').value || 'Your Name'}</h3>
155
+ <p>${document.getElementById('email').value || '[email protected]'} |
156
+ ${document.getElementById('phone').value || '(123) 456-7890'}</p>
157
+ <h4>Professional Summary</h4>
158
+ <p>${document.getElementById('summary').value || 'Experienced professional seeking new opportunities.'}</p>
159
+ <h4>Work Experience</h4>
160
+ <div class="preview-experience">
161
+ ${Array.from(document.querySelectorAll('.experience-entry')).map(exp => `
162
+ <h5>${exp.querySelector('.job-title').value || 'Job Title'} at ${exp.querySelector('.company').value || 'Company'}</h5>
163
+ <p>${exp.querySelector('.duration').value || 'Duration'}</p>
164
+ <p>${exp.querySelector('.description').value || 'Job description and accomplishments.'}</p>
165
+ `).join('')}
166
+ </div>
167
+ `;
168
+ });
169
+
170
+ // Analyze Resume
171
+ document.getElementById('analyze-resume').addEventListener('click', function() {
172
+ // In a real app, you would call your backend API for analysis
173
+ alert('In a complete app, this would analyze your resume for ATS compatibility and suggest improvements.');
174
+ });
175
+
176
+ // Download PDF
177
+ document.getElementById('download-pdf').addEventListener('click', function() {
178
+ // In a real app, you would generate a PDF
179
+ alert('In a complete app, this would generate and download a PDF of your resume.');
180
+ });
181
+ });
templates/index.html ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Resume Builder</title>
7
+ <link rel="stylesheet" href="../static/css/style.css">
8
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet">
9
+ </head>
10
+ <body>
11
+ <div class="container">
12
+ <header>
13
+ <h1>AI-Powered Resume Builder</h1>
14
+ <p>Create the perfect resume that gets you hired</p>
15
+ </header>
16
+
17
+ <div class="builder-container">
18
+ <div class="resume-form">
19
+ <h2>Your Information</h2>
20
+
21
+ <div class="form-section" draggable="true">
22
+ <h3>Personal Details</h3>
23
+ <input type="text" id="name" placeholder="Full Name">
24
+ <input type="text" id="email" placeholder="Email">
25
+ <input type="text" id="phone" placeholder="Phone">
26
+ <input type="text" id="linkedin" placeholder="LinkedIn URL">
27
+ </div>
28
+
29
+ <div class="form-section" draggable="true">
30
+ <h3>Summary</h3>
31
+ <textarea id="summary" placeholder="Professional summary"></textarea>
32
+ <button class="ai-suggest" data-for="summary">Get AI Suggestions</button>
33
+ </div>
34
+
35
+ <div class="form-section" draggable="true">
36
+ <h3>Work Experience</h3>
37
+ <div class="experience-entry">
38
+ <input type="text" class="job-title" placeholder="Job Title">
39
+ <input type="text" class="company" placeholder="Company">
40
+ <input type="text" class="duration" placeholder="Duration">
41
+ <textarea class="description" placeholder="Job Description"></textarea>
42
+ <button class="ai-suggest" data-for="experience">Improve with AI</button>
43
+ </div>
44
+ <button id="add-experience">+ Add Another</button>
45
+ </div>
46
+
47
+ <div class="form-section" draggable="true">
48
+ <h3>Education</h3>
49
+ <input type="text" id="degree" placeholder="Degree">
50
+ <input type="text" id="university" placeholder="University">
51
+ <input type="text" id="grad-year" placeholder="Graduation Year">
52
+ </div>
53
+
54
+ <div class="form-section" draggable="true">
55
+ <h3>Skills</h3>
56
+ <div class="skills-container">
57
+ <input type="text" id="skills-input" placeholder="Add skill">
58
+ <button id="add-skill">+ Add</button>
59
+ </div>
60
+ <div id="skills-list"></div>
61
+ </div>
62
+
63
+ <div class="actions">
64
+ <button id="analyze-resume">Analyze & Improve</button>
65
+ <button id="download-pdf">Download PDF</button>
66
+ <button id="preview-resume">Preview Resume</button>
67
+ </div>
68
+ </div>
69
+
70
+ <div class="resume-preview">
71
+ <h2>Resume Preview</h2>
72
+ <div id="preview-content"></div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+
77
+ <!-- AI Suggestions Modal -->
78
+ <div id="ai-modal" class="modal">
79
+ <div class="modal-content">
80
+ <span class="close">&times;</span>
81
+ <h3>AI Suggestions</h3>
82
+ <div id="ai-suggestions"></div>
83
+ <button id="apply-suggestion">Apply Suggestion</button>
84
+ </div>
85
+ </div>
86
+
87
+ <script src="../static/js/script.js"></script>
88
+ </body>
89
+ </html>