Skip to content

Commit

Permalink
Merge pull request #134 from CMU-17313Q/integration-python-microservi…
Browse files Browse the repository at this point in the history
…ce-flask

Integration python microservice flask
  • Loading branch information
LujainAlMansoori authored Nov 11, 2023
2 parents b2d4bed + a5862cc commit 55b6e79
Show file tree
Hide file tree
Showing 18 changed files with 597 additions and 17 deletions.
Binary file added node_modules/career-model/model.pkl
Binary file not shown.
96 changes: 96 additions & 0 deletions node_modules/career-model/predict.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions node_modules/career-model/requirements.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

112 changes: 112 additions & 0 deletions public/src/client/career.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use strict';

define('forum/career', [
'translator', 'jquery-form',
], function (translator) {
const Career = {};
let validationError = false;

Career.init = function () {
const student_id = $('#student_id');
const age = $('#age');
const gpa = $('#gpa');
const num_programming_languages = $('#num_programming_languages');
const num_past_internships = $('#num_past_internships');
const signup = $('#signup');

function validateForm(callback) {
validationError = false;
validateNonEmpty(student_id.val(), $('#student-id-notify'));
validateRangedInt(age.val(), $('#age-notify'), 18, 25);
validateRangedFloat(gpa.val(), $('#gpa-notify'), 0.0, 4.0);
validateRangedInt(num_programming_languages.val(), $('#num-programming-languages-notify'), 1, 5);
validateRangedInt(num_past_internships.val(), $('#num-past-internships-notify'), 0, 4);
callback();
}

signup.on('click', function (e) {
const registerBtn = $(this);
const errorEl = $('#career-error-notify');
errorEl.addClass('hidden');
e.preventDefault();
validateForm(function () {
if (validationError) {
return;
}

registerBtn.addClass('disabled');

registerBtn.parents('form').ajaxSubmit({
headers: {
'x-csrf-token': config.csrf_token,
},
success: function () {
location.reload();
},
error: function (data) {
translator.translate(data.responseText, config.defaultLang, function (translated) {
if (data.status === 403 && data.responseText === 'Forbidden') {
window.location.href = config.relative_path + '/career?error=csrf-invalid';
} else {
errorEl.find('p').text(translated);
errorEl.removeClass('hidden');
registerBtn.removeClass('disabled');
}
});
},
});
});
});
};

function validateNonEmpty(value, value_notify) {
if (!value || value.length === 0) {
showError(value_notify, 'Must be non-empty');
} else {
showSuccess(value_notify);
}
}

function validateRangedInt(value, value_notify, min_val, max_val) {
if (!value || isNaN(value)) {
showError(value_notify, `Must be a valid integer`);
} else if (parseInt(value, 10) < min_val || parseInt(value, 10) > max_val) {
showError(value_notify, `Must be within the range [${min_val}, ${max_val}]`);
} else {
showSuccess(value_notify);
}
}

function validateRangedFloat(value, value_notify, min_val, max_val) {
if (!value || isNaN(value)) {
showError(value_notify, `Must be a valid floating point value`);
} else if (parseFloat(value) < min_val || parseFloat(value) > max_val) {
showError(value_notify, `Must be within the range [${min_val}, ${max_val}]`);
} else {
showSuccess(value_notify);
}
}

function showError(element, msg) {
translator.translate(msg, function (msg) {
element.html(msg);
element.parent()
.removeClass('register-success')
.addClass('register-danger');
element.show();
});
validationError = true;
}

function showSuccess(element, msg) {
translator.translate(msg, function (msg) {
element.html(msg);
element.parent()
.removeClass('register-danger')
.addClass('register-success');
element.show();
});
}

return Career;
});
11 changes: 11 additions & 0 deletions public/src/modules/helpers.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ module.exports = function (utils, Benchpress, relative_path) {
userAgentIcons,
buildAvatar,
register,
getPredictionColor,
formatPrediction,
__escape: identity,
};

Expand Down Expand Up @@ -336,6 +338,15 @@ module.exports = function (utils, Benchpress, relative_path) {
styles.push('background-color: ' + userObj['icon:bgColor'] + ';');
return '<span ' + attributes.join(' ') + ' style="' + styles.join(' ') + '">' + userObj['icon:text'] + '</span>';
}
function getPredictionColor(prediction) {
if (prediction === 1) { return `"background-color: rgb(0, 255, 0);"`; }
return `"background-color: rgb(255, 0, 0);"`;
}

function formatPrediction(prediction) {
return prediction;
}


function register() {
Object.keys(helpers).forEach(function (helperName) {
Expand Down
5 changes: 1 addition & 4 deletions src/controllers/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,9 @@ authenticationController.register = async function (req, res) {
if (userData.password.length > 512) {
throw new Error('[[error:password-too-long]]');
}

if (!userData['account-type'] ||
(userData['account-type'] !== 'student' && userData['account-type'] !== 'instructor')) {
if (!userData['account-type'] || (userData['account-type'] !== 'student' && userData['account-type'] !== 'instructor' && userData['account-type'] !== 'recruiter')) {
throw new Error('Invalid account type');
}

user.isPasswordValid(userData.password);

res.locals.processLogin = true; // set it to false in plugin if you wish to just register only
Expand Down
8 changes: 0 additions & 8 deletions src/controllers/career.js

This file was deleted.

28 changes: 28 additions & 0 deletions src/controllers/careers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

const user = require('../user');
const helpers = require('./helpers');

const careerController = module.exports;

careerController.get = async function (req, res) {
const userData = await user.getUserFields(req.uid, ['accounttype']);

const accountType = userData.accounttype;
let careerData = {};

if (accountType === 'recruiter') {
careerData.allData = await user.getAllCareerData();
} else {
const userCareerData = await user.getCareerData(req.uid);
if (userCareerData) {
careerData = userCareerData;
} else {
careerData.newAccount = true;
}
}

careerData.accountType = accountType;
careerData.breadcrumbs = helpers.buildBreadcrumbs([{ text: 'Career', url: '/career' }]);
res.render('career', careerData);
};
3 changes: 2 additions & 1 deletion src/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Controllers.ping = require('./ping');
Controllers.home = require('./home');
Controllers.topics = require('./topics');
Controllers.posts = require('./posts');
Controllers.career = require('./career');
Controllers.careers = require('./careers');
Controllers.categories = require('./categories');
Controllers.category = require('./category');
Controllers.unread = require('./unread');
Expand Down Expand Up @@ -188,6 +188,7 @@ Controllers.register = async function (req, res, next) {
<select class="form-control" name="account-type" aria-label="Account Type">
<option value="student" selected>Student</option>
<option value="instructor">Instructor</option>
<option value="recruiter">Recruiter</option>
</select>
`,
},
Expand Down
54 changes: 54 additions & 0 deletions src/controllers/write/career.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict';

const helpers = require('../helpers');
const user = require('../../user');
const db = require('../../database');

const Career = module.exports;
Career.register = async function (req, res) {
const userData = req.query;
try {
// Forward the request to the Flask application
// console.log(userData.student_id);
const flaskResponse = await fetch('http://127.0.0.1:5000/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Include any other necessary headers
},
body: JSON.stringify({
student_id: userData.student_id,
major: userData.major,
age: userData.age,
gender: userData.gender,
gpa: userData.gpa,
extra_curricular: userData.extra_curricular,
num_programming_languages: userData.num_programming_languages,
num_past_internships: userData.num_past_internships,
}),
});

const userCareerData = {
student_id: userData.student_id,
major: userData.major,
age: userData.age,
gender: userData.gender,
gpa: userData.gpa,
extra_curricular: userData.extra_curricular,
num_programming_languages: userData.num_programming_languages,
num_past_internships: userData.num_past_internships,
};
if (!flaskResponse.ok) {
throw new Error('Failed to get prediction from Flask app.');
}
const predictionResult = await flaskResponse.json();
console.log(predictionResult);
userCareerData.prediction = predictionResult.good_employee;
await user.setCareerData(req.uid, userCareerData);
db.sortedSetAdd('users:career', req.uid, req.uid);
res.json({});
} catch (err) {
console.log(err);
helpers.noScriptErrors(req, res, err.message, 400);
}
};
Loading

0 comments on commit 55b6e79

Please sign in to comment.