backend/main.js

135 lines
4.8 KiB
JavaScript
Raw Permalink Normal View History

2023-06-06 05:06:06 +00:00
require('dotenv').config()
const express = require("express");
const fileUpload = require("express-fileupload");
const pdfParse = require("pdf-parse");
const cors = require('cors');
const cheerio = require('cheerio');
const chat = require('./api');
const PocketBase = require('pocketbase/cjs');
const { Configuration, OpenAIApi } = require("openai");
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const app = express();
const pb = new PocketBase("https://pocketbase.omersabic.com")
app.use(cors());
app.use(fileUpload());
const supportedAds = ['www.azubiyo.de']
app.post("/create-letter", async (req, res) => {
if (!req.files && !req.files.pdfFile || !req.body.job || !req.body.extra || !req.body.language || !req.body.auth) {
res.status(400);
res.end();
}
// Check user auth token and tokens quantity
pb.authStore.save(req.body.auth, null);
await pb.collection("users").authRefresh()
if (pb.authStore.model.tokens < 1) {
return res.send({ error: "not enough tokens", content: "You don't have enough tokens to run this service." })
}
await pb.collection('users').update(pb.authStore.model.id, {
tokens: pb.authStore.model.tokens - 1
});
let parsedURL = new URL(req.body.job);
if (!supportedAds.includes(parsedURL.host)) throw Error(`We don't support ${parsedURL.host} job postings for now.`);
let parsedCV = await parsePDF(req.files.pdfFile);
let jobAd = await scrapeJobAd(req.body.job);
let prompt = createPrompt(parsedCV, jobAd, req.body.extra, parsedURL.host);
let finishedLetter = await writeLetter(prompt, req.body.language)
await pb.collection('letters').create({
user: pb.authStore.model.id,
content: finishedLetter
})
res.send({ content: finishedLetter });
});
app.get("/test", async (req, res) => {
let result = await chat.create([
{
"content": "You are ChatGPT, a large language model trained by OpenAI.\nCarefully heed the user's instructions. \nRespond using Markdown.",
"role": "system"
},
{ "role": "user", "content": "What is the sum of 2+2" }
]);
res.send(result);
})
async function writeLetter(prompt, language) {
// try {
// // let result = await chat.create(prompt);
// let result = "test result so I don't waste money on openai"
// return result;
// }
// catch (e) {
// console.log(e)
// }
return (await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [
{ "role": "system", "content": `You are a career advisor, you help people get jobs by writing their cover letters.\nCarefully heed the provided data. \nRespond only with the cover letter and no additional content. Make the cover letters appeal towards the job description. Write in ${language}`},
{ "role": "user", "content": prompt}
],
temperature: 1,
max_tokens: 1500
})).data.choices[0].message.content;
}
async function scrapeJobAd(url) {
let parsedURL = new URL(url);
if (parsedURL.host !== "www.azubiyo.de") throw Error('We only support azubiyo.de job postings for now.');
let data = await (await fetch(url)).text()
const $ = cheerio.load(data);
$('.stellenanzeige-content style').remove()
return $('.stellenanzeige-content').text()
}
async function parsePDF(file) {
return (await pdfParse(file)).text
}
function createPrompt(cv, job, extra, jobAdURL) {
// return [
// { "role": "system", "content": "You are a career advisor, you help people get jobs by writing their cover letters.\nCarefully heed the provided data. \nRespond only with the cover letter and no additional content."},
// // { "role": "user", "content": `CV: ${cv}` },
// // { "role": "user", "content": `Job Ad (found on ${jobAdURL}: ${job}` },
// // { "role": "user", "content": `Extra information: ${extra}` },
// { "role": "user", "content": "Please generate a compelling cover letter that highlights the person's skills, experiences, and suitability for the job position. Make sure to mention specific qualifications and align the cover letter with the requirements mentioned in the job ad. Keep the letter to 1 page at the longest. Write a unique opening paragraph. Don't copy text directly from the job ad.`" }
// ]
return `Generate a cover letter for a job application based on the following information:
CV (parsed from PDF): ${cv}
Job (found on ${jobAdURL}): ${job}
Extra infromation: ${extra}
Please generate a compelling cover letter that highlights the person's skills, experiences, and suitability for the job position. Make sure to mention specific qualifications and align the cover letter with the requirements mentioned in the job ad. Keep the letter to 1 page at the longest. Write a unique opening paragraph. Don't copy text directly from the job ad.`
}
app.listen(process.env.PORT);