-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
370 lines (338 loc) · 14 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AI Cover Letter Generator</title>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5733428460091370"
crossorigin="anonymous"></script>
<link href="/static/styles.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Averia+Serif+Libre:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&family=Graduate&family=Righteous&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "hglayf4rr7");
</script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WKGZMZ1GHN"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-WKGZMZ1GHN');
</script>
</head>
<body>
<div class="container">
<div id="container-bg" class="container-bg"></div>
<h1 class="text-center my-4">AI Cover Letter Generator</h1>
<div class="instruction">
<p>Enter your <b>full LinkedIn profile URL</b> and <b>job offer URL (not from linkedIn, please use the URL from the actual job offer)</b>. Click on 'Generate Cover Letter' and wait a few moments. A personalized cover letter will be generated for you in less than a minute ! 🤩 </p>
</div>
<div class="tips">
<p>For best results, make sure your linkedIn profile's visibility is set to "Public" during the process. 🔍 (Settings>Visibility>Allow all)</p>
</div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="error">
<div class="flashed-messages">
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endwith %}
<form method="POST">
<div id=url-input class="form-group">
<label for="resume">
<i class="fa-regular fa-file-alt"></i> Resume: </label>
<!-- === File Upload === -->
<div id="FileUpload">
<div class="wrapper">
<div class="upload">
<p>Drop pdf here or<span class="upload__button">Browse</span></p>
<p id="resume_name"></p>
<input type="file" class="form-control" id="resume" name="resume" accept=".pdf" required style="display: none;">
</div>
<!-- The following divs display the progress of uploaded files -->
<div class="uploaded uploaded--one" style="display: none;">
<i class="far fa-file-pdf"></i>
<div class="file">
<div class="file__name">
<p id="filename1"></p>
<i class="fas fa-times"></i>
</div>
<div class="progress">
<div class="progress-bar bg-success progress-bar-striped progress-bar-animated" id="progress1" style="width:0%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id=url-input class="form-group">
<label for="job_offer">
<i class="fa-regular fa-building"></i> Job Offer: </label>
<input type="url" class="form-control" id="job_offer_url" name="job_offer_url" rows="4" placeholder="https://your-dream-company.com/jobs/your-dream-job/" required>
</div>
<input type="hidden" id="scraped_data" name="scraped_data">
<div class="form-group">
<label for="language">
<i class="fa-solid fa-language"></i> Choose a language for your cover letter: </label>
<select id="language" name="language" class="form-control">
<option selected value="english">English</option>
<option value="chinese">Chinese</option>
<option value="spanish">Spanish</option>
<option value="french">French</option>
<option value="german">German</option>
<option value="italian">Italian</option>
<option value="dutch">Dutch</option>
<option value="russian">Russian</option>
<option value="japanese">Japanese</option>
<option value="korean">Korean</option>
<option value="portuguese">Portuguese</option>
</select>
</div>
<button id="submit-button" type="submit" class="btn btn-primary btn-lg btn-block"><i class="bi bi-envelope-paper"></i> Generate Cover Letter</button>
<canvas id="containerpoints" width="50" height="50" style="display: none;"></canvas>
<div id="loading" style="display: none;">
<span id="countdown">40 seconds left</span>
</div>
<div class="container-footer" text-align="center">
<span> Made in Paris with ❤️, we wish you luck with your job hunting !</span><br>
</div>
</form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/5bd3dc603d.js" crossorigin="anonymous"></script>
<script>
$(document).ready(function() {
// ... existing jQuery code ...
// File upload handling
const uploadButton = document.querySelector(".upload__button");
const fileInput = document.querySelector("#resume");
uploadButton.addEventListener("click", () => {
fileInput.click();
});
fileInput.addEventListener("change", () => {
const file = fileInput.files[0];
if (file) {
uploadFile(file);
document.getElementById('resume_name').innerText = "Selected file: " + file.name;
}
});
fileInput.addEventListener("change", () => {
const file = fileInput.files[0];
if (file) {
uploadFile(file);
}
});
async function uploadFile(file) {
// Hide the text and the browse button
document.querySelector('.upload p').style.display = 'none';
document.querySelector('.upload__button').style.display = 'none';
const formData = new FormData();
formData.append("file", file);
const response = await fetch("/upload", {
method: "POST",
body: formData
});
if (response.ok) {
console.log("File uploaded successfully.");
} else {
console.error("File upload failed.");
}
}
});
</script>
<script>
var points = [],
velocity2 = 5, // velocity squared
canvas = document.getElementById('containerpoints'),
context = canvas.getContext('2d'),
radius = 2,
boundaryX = 50,
boundaryY = 50,
numberOfPoints = 20;
init();
function init() {
// create points
for (var i = 0; i < numberOfPoints; i++) {
createPoint();
}
// create connections
for (var i = 0, l = points.length; i < l; i++) {
var point = points[i];
if (i == 0) {
points[i].buddy = points[points.length - 1];
} else {
points[i].buddy = points[i - 1];
}
}
// animate
animate();
}
function createPoint() {
var point = {},
vx2, vy2;
point.x = Math.random() * boundaryX;
point.y = Math.random() * boundaryY;
// random vx
point.vx = (Math.floor(Math.random()) * 2 - 1) * Math.random();
vx2 = Math.pow(point.vx, 2);
// vy^2 = velocity^2 - vx^2
vy2 = velocity2 - vx2;
point.vy = Math.sqrt(vy2) * (Math.random() * 2 - 1);
points.push(point);
}
function resetVelocity(point, axis, dir) {
var vx, vy;
if (axis == 'x') {
point.vx = dir * Math.random();
vx2 = Math.pow(point.vx, 2);
// vy^2 = velocity^2 - vx^2
vy2 = velocity2 - vx2;
point.vy = Math.sqrt(vy2) * (Math.random() * 2 - 1);
} else {
point.vy = dir * Math.random();
vy2 = Math.pow(point.vy, 2);
// vy^2 = velocity^2 - vx^2
vx2 = velocity2 - vy2;
point.vx = Math.sqrt(vx2) * (Math.random() * 2 - 1);
}
}
function drawCircle(x, y) {
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = '#0576ef';
context.fill();
}
function drawLine(x1, y1, x2, y2) {
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.strokeStyle = '#3697ff'
context.stroke();
}
function draw() {
for (var i = 0, l = points.length; i < l; i++) {
// circles
var point = points[i];
point.x += point.vx;
point.y += point.vy;
drawCircle(point.x, point.y);
// lines
drawLine(point.x, point.y, point.buddy.x, point.buddy.y);
// check for edge
if (point.x < 0 + radius) {
resetVelocity(point, 'x', 1);
} else if (point.x > boundaryX - radius) {
resetVelocity(point, 'x', -1);
} else if (point.y < 0 + radius) {
resetVelocity(point, 'y', 1);
} else if (point.y > boundaryY - radius) {
resetVelocity(point, 'y', -1);
}
}
}
function animate() {
context.clearRect(0, 0, 200, 200);
draw();
requestAnimationFrame(animate);
}
$(document).ready(function() {
// Check for saved data in local storage
if (localStorage.getItem("profile")) {
$('#profile').val(localStorage.getItem("profile"));
}
if (localStorage.getItem("job_offer")) {
$('#job_offer').val(localStorage.getItem("job_offer"));
}
// When the form is submitted
$('form').on('submit', function(e) {
// Prevent the form from being submitted normally
e.preventDefault();
// Show the loader and counter
$('#loading').css('display', 'block');
$('#containerpoints').css('display', 'block');
// Hide the submit button
$('#submit-button').css('display', 'none');
console.log("Form submitted."); // Debugging line
// Start the counter
var timeleft = 40;
var downloadTimer = setInterval(function() {
if (timeleft <= 0) {
clearInterval(downloadTimer);
document.getElementById("countdown").innerHTML = "Processing...";
} else {
document.getElementById("countdown").innerHTML = timeleft + " seconds left";
}
timeleft -= 1;
}, 1000);
console.log("Counter started."); // Debugging lines
var job_offer_url = "{{ job_offer_url }}";
console.log(job_offer_url);
// Start the border animation
document.getElementById('container-bg').style.display = 'block';
document.getElementById('container-bg').style.animation = 'reveal-bg 40s linear forwards';
// Save data to local storage
localStorage.setItem("profile", $('#profile').val());
localStorage.setItem("job_offer", $('#job_offer').val());
// Get the form data
let formData = $("form").serializeArray();
// Send the form data to the back-end
$.ajax({
url: '/generate',
type: 'POST',
data: new FormData($("form")[0]),
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
success: function(response) {
// Handle success case
if (response.success) {
var task_id = response.task_id; // Capture the task_id from the response
// Polling function
var poll = function() {
$.ajax({
url: '/check_status',
type: 'GET',
data: { 'task_id': task_id },
success: function(data) {
console.log(data); // Log the whole data object
if (data.ready) {
window.location.href = '/result'; // Redirect to the result page
} else {
// If not ready, poll again after a delay
setTimeout(poll, 5000);
}
},
error: function(jqXHR, textStatus, errorThrown) {
// Handle error case
alert('An error occurred: ' + textStatus + ' ' + errorThrown);
}
});
};
poll(); // Start the polling process
} else {
// Display error message to the user
alert(response.message);
}
},
error: function(jqXHR, textStatus, errorThrown) {
// Handle error case
alert('An error occurred: ' + textStatus + ' ' + errorThrown);
}
});
});
});
</script>
</body>
</html>