Fixed .pdf resume upload, Logout button background
This commit is contained in:
parent
49b03eb083
commit
7f71b0357f
@ -8,11 +8,12 @@ import sqlite3 from 'sqlite3';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import multer from 'multer';
|
||||
import mammoth from 'mammoth';
|
||||
import { fileURLToPath } from 'url';
|
||||
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.js';
|
||||
import pkg from 'pdfjs-dist';
|
||||
|
||||
import OpenAI from 'openai';
|
||||
|
||||
// --- Basic file init ---
|
||||
@ -28,6 +29,7 @@ dotenv.config({ path: envPath }); // Load .env file
|
||||
const app = express();
|
||||
const PORT = process.env.PREMIUM_PORT || 5002;
|
||||
|
||||
const { getDocument } = pkg;
|
||||
|
||||
let db;
|
||||
const initDB = async () => {
|
||||
@ -1655,6 +1657,22 @@ ${resumeText}
|
||||
Precisely Tailored, ATS-Optimized Resume:
|
||||
`;
|
||||
|
||||
async function extractTextFromPDF(filePath) {
|
||||
const fileBuffer = await fs.readFile(filePath);
|
||||
const uint8Array = new Uint8Array(fileBuffer); // Convert Buffer explicitly
|
||||
const pdfDoc = await getDocument({ data: uint8Array }).promise;
|
||||
|
||||
let text = '';
|
||||
for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {
|
||||
const page = await pdfDoc.getPage(pageNum);
|
||||
const pageText = await page.getTextContent();
|
||||
text += pageText.items.map(item => item.str).join(' ');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
// Your corrected endpoint with limits correctly returned:
|
||||
app.post(
|
||||
'/api/premium/resume/optimize',
|
||||
upload.single('resumeFile'),
|
||||
@ -1668,7 +1686,6 @@ app.post(
|
||||
|
||||
const userId = req.userId;
|
||||
const now = new Date();
|
||||
const currentWeek = getWeekNumber(now); // Function defined below
|
||||
|
||||
const userProfile = await db.get(
|
||||
`SELECT is_premium, is_pro_premium, resume_optimizations_used, resume_limit_reset, resume_booster_count
|
||||
@ -1702,16 +1719,20 @@ app.post(
|
||||
}
|
||||
|
||||
const filePath = req.file.path;
|
||||
const fileExt = req.file.originalname.split('.').pop().toLowerCase();
|
||||
const mimeType = req.file.mimetype;
|
||||
|
||||
let resumeText = '';
|
||||
if (fileExt === 'pdf') {
|
||||
if (mimeType === 'application/pdf') {
|
||||
resumeText = await extractTextFromPDF(filePath);
|
||||
} else if (fileExt === 'docx') {
|
||||
} else if (
|
||||
mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||
mimeType === 'application/msword'
|
||||
) {
|
||||
const result = await mammoth.extractRawText({ path: filePath });
|
||||
resumeText = result.value;
|
||||
} else {
|
||||
return res.status(400).json({ error: 'Unsupported file type.' });
|
||||
await fs.unlink(filePath);
|
||||
return res.status(400).json({ error: 'Unsupported or corrupted file upload.' });
|
||||
}
|
||||
|
||||
const prompt = buildResumePrompt(resumeText, jobTitle, jobDescription);
|
||||
@ -1729,11 +1750,15 @@ app.post(
|
||||
[userId]
|
||||
);
|
||||
|
||||
// Calculate remaining optimizations
|
||||
const remainingOptimizations = totalLimit - (userProfile.resume_optimizations_used + 1);
|
||||
|
||||
fs.unlinkSync(filePath);
|
||||
res.json({ optimizedResume, remainingOptimizations });
|
||||
await fs.unlink(filePath);
|
||||
res.json({
|
||||
optimizedResume,
|
||||
remainingOptimizations,
|
||||
resetDate: resetDate.toISOString() // <-- explicitly returned here!
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error optimizing resume:', err);
|
||||
res.status(500).json({ error: 'Failed to optimize resume.' });
|
||||
|
@ -237,7 +237,7 @@ function App() {
|
||||
{/* Logout */}
|
||||
<li>
|
||||
<button
|
||||
className="text-red-600 hover:text-red-800"
|
||||
className="text-red-600 hover:text-red-800 bg-transparent border-none"
|
||||
onClick={handleLogout}
|
||||
>
|
||||
Logout
|
||||
|
@ -9,6 +9,7 @@ function ResumeRewrite() {
|
||||
const [error, setError] = useState('');
|
||||
const [remainingOptimizations, setRemainingOptimizations] = useState(null);
|
||||
const [resetDate, setResetDate] = useState(null);
|
||||
const [loading, setLoading] = useState(false); // ADDED loading state
|
||||
|
||||
const handleFileChange = (e) => {
|
||||
setResumeFile(e.target.files[0]);
|
||||
@ -39,6 +40,8 @@ function ResumeRewrite() {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true); // ACTIVATE loading
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
const formData = new FormData();
|
||||
@ -55,12 +58,12 @@ function ResumeRewrite() {
|
||||
|
||||
setOptimizedResume(res.data.optimizedResume || '');
|
||||
setError('');
|
||||
|
||||
// Refresh remaining optimizations after optimizing
|
||||
fetchRemainingOptimizations();
|
||||
} catch (err) {
|
||||
console.error('Resume optimization error:', err);
|
||||
setError(err.response?.data?.error || 'Failed to optimize resume.');
|
||||
} finally {
|
||||
setLoading(false); // DEACTIVATE loading
|
||||
}
|
||||
};
|
||||
|
||||
@ -101,10 +104,22 @@ function ResumeRewrite() {
|
||||
|
||||
{error && <p className="text-red-600 font-semibold">{error}</p>}
|
||||
|
||||
<button type="submit"
|
||||
className="inline-block bg-blue-600 text-white font-semibold px-5 py-2 rounded hover:bg-blue-700 transition-colors">
|
||||
Optimize Resume
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className={`inline-block font-semibold px-5 py-2 rounded transition-colors ${
|
||||
loading ? 'bg-gray-400 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700'
|
||||
} text-white`}
|
||||
>
|
||||
{loading ? 'Optimizing Resume...' : 'Optimize Resume'}
|
||||
</button>
|
||||
|
||||
{loading && (
|
||||
<div className="flex items-center justify-center mt-4">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500"></div>
|
||||
<span className="ml-3 text-blue-700 font-semibold">Optimizing your resume...</span>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
|
||||
{optimizedResume && (
|
||||
|
BIN
uploads/27bb962c438a8ffe986fc7571948bfb7
Normal file
BIN
uploads/27bb962c438a8ffe986fc7571948bfb7
Normal file
Binary file not shown.
BIN
uploads/7494904b7764d12ecd6900f9292949f2
Normal file
BIN
uploads/7494904b7764d12ecd6900f9292949f2
Normal file
Binary file not shown.
BIN
uploads/9fce92f8988efce8891352b7d64b2829
Normal file
BIN
uploads/9fce92f8988efce8891352b7d64b2829
Normal file
Binary file not shown.
BIN
uploads/b4299293be37c7a453d27801078a4efb
Normal file
BIN
uploads/b4299293be37c7a453d27801078a4efb
Normal file
Binary file not shown.
BIN
uploads/d0470483ed235e9d1a88bee2005dd840
Normal file
BIN
uploads/d0470483ed235e9d1a88bee2005dd840
Normal file
Binary file not shown.
BIN
user_profile.db
BIN
user_profile.db
Binary file not shown.
Loading…
Reference in New Issue
Block a user