Skip to content

Commit

Permalink
Merge pull request #101 from Arquisoft/service_question_generator
Browse files Browse the repository at this point in the history
Questions Services major upgrade
  • Loading branch information
marco-qg authored Apr 11, 2024
2 parents a83ff63 + e697ee1 commit aad6f55
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const express = require('express');
const cors = require('cors');
const axios = require('axios');
const mongoose = require('mongoose');
const { Pais } = require('./questiongenerator-model')
const { QuestionGenerator } = require('./questiongenerator')

const app = express();
const port = 8007;
Expand All @@ -22,69 +22,47 @@ app.use(express.json());
// Middleware to enable CORS (cross-origin resource sharing). In order for the API to be accessible by other origins (domains).
app.use(cors());

function shuffle(array) {
let currentIndex = array.length;
let randomIndex;
// Mientras queden elementos para mezclar.
while (currentIndex > 0) {
// Escoge un elemento aleatorio.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// Intercambia el elemento actual con el elemento aleatorio.
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array;
}
// Only parse query parameters into strings, not objects (adds security)
app.set('query parser', 'simple');

async function generateQuestion() {
var elementos = await Pais.find({ capital: { $exists: true } }).exec();
console.log("Find:\n" + elementos)
elementos = shuffle(elementos);
var mockedQuestions = [{
pregunta: "¿Cual es la capital de " + elementos[0].pais + "?",
respuesta_correcta: elementos[0].capital,
respuestas_incorrectas: [elementos[1].capital, elementos[2].capital, elementos[3].capital]
}];
console.log(mockedQuestions);
return mockedQuestions
function validateNumberInQuery(number, minValue, paramName, defValue) {
if (!(paramName in number)) return defValue;
n = Number(number[paramName]);
if (isNaN(n)) throw new Error(`A number was expected in param \'${paramName}\'`);
if (n < minValue) throw new Error(`\'${paramName}\' must be at least \'${minValue}\'`);
return n;
}

// Function to generate the required number of questions
async function getQuestions(req) {
const { n_preguntas, n_respuestas, tema } = req.query;
var preguntas = Number(n_preguntas);
var respuestas = Number(n_respuestas);
var temas = String(tema);

// if (isNaN(preguntas)) {
// generateQuestion()
// console.log("merda", mockedQuestions)
// return mockedQuestions.slice(0, 4);
// }
// const response = [];
// generateQuestion();
// for (let i = 0; i < preguntas; i++) {
// response.push(mockedQuestions[i % 11]);
// }
return await generateQuestion();
// Function to validate required fields in the request body
function validateFields(query) {
const preguntas = validateNumberInQuery(query, 1, 'n_preguntas', 1);
const respuestas = validateNumberInQuery(query, 1, 'n_respuestas', 4);
var temas = query.tema || [];
if (!Array.isArray(temas)) {
temas = Array.of(temas);
}
return { preguntas, respuestas, temas };
}

// Route for getting questions
app.get('/questions', async (req, res) => {
try {
// TODO: Implement logic to fetch questions from MongoDB and send response
// const questions = await Question.find()
const defaultQuestion = await getQuestions(req);

try{
const questionsHistoryResponse = await axios.post(questionHistoryServiceUrl + '/history/questions', defaultQuestion);
const { preguntas, respuestas, temas } = validateFields(req.query);
try {
const retQuestions = await QuestionGenerator.generateQuestions(preguntas, respuestas, temas);
try {
await axios.post(questionHistoryServiceUrl + '/history/questions', retQuestions);
} catch (error) {
console.error(`Error saving questions history: ${error}`);
}
res.json(retQuestions);
} catch (error) {
console.error(`Error saving questions history: ${error}`);
console.error(`An error occurred: ${error.message}`);
res.status(500).json({ error: 'Internal Server Error' });
}
res.json(defaultQuestion);
} catch (error) {
// res.status(500).json({ message: error.message })
res.status(500).json({ error: 'Internal Server Error' });
console.error(`Bad Request: ${error.message}`);
res.status(400).json({ message: error.message });
}
});

Expand Down
101 changes: 101 additions & 0 deletions questionsservice/questiongeneratorservice/questiongenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const { Pais } = require('./questiongenerator-model')

class QuestionGenerator {

static temas = new Map([
["paises", [0, 1, 2]],
['capital', [0]],
["lenguaje", [1]]
]);
;

static plantillas = [
{
pregunta: (param) => `¿Cual es la capital de ${param}?`,
filtro: { capital: { $exists: true } },
campo_pregunta: 'pais',
campo_respuesta: 'capital'
},
{
pregunta: (param) => `¿Qué lengua se habla en ${param}?`,
filtro: { lenguaje: { $exists: true } },
campo_pregunta: 'pais',
campo_respuesta: 'lenguaje'
}
// {
// pregunta: (param) => `¿Cuál es la bandera de ${param}?`,
// filtro: { bandera: { $exists: true } },
// campo_pregunta: 'pais',
// campo_respuesta: 'bandera'
// }
];

static async generateQuestion(plantilla, respuestas) {
console.log("\nPlantilla:");
console.log(plantilla);

const randomDocs = await Pais.aggregate([
{ $match: plantilla.filtro },
{ $sample: { size: respuestas } }
]);
if (randomDocs.length < respuestas) {
console.error(`Not enought data found to generate a question`);
throw new Error(`Not enought data found to generate a question`);
}

console.log("\nFind:");
console.log(randomDocs);

var retQuestion = {
pregunta: plantilla.pregunta(randomDocs[0][plantilla.campo_pregunta]),
respuesta_correcta: randomDocs[0][plantilla.campo_respuesta],
respuestas_incorrectas: Array.from({ length: respuestas-1 }, (_, i) => randomDocs[i+1][plantilla.campo_respuesta])
};
console.log("\nPregunta generada:");
console.log(retQuestion);

return retQuestion;
}

static async generateQuestions(preguntas, respuestas, temas) {
console.log(temas);
const plantillasDisponibles = this.getAvailableTemplates(temas);
console.log(plantillasDisponibles);
var retQuestions = [];
for (let i = 0; i < preguntas; i++) {
let index = Math.floor(Math.random() * plantillasDisponibles.length);
retQuestions.push(await this.generateQuestion(this.plantillas[plantillasDisponibles[index]], respuestas));
}
return retQuestions;
}

static getAvailableTemplates(temas) {
if (temas.length == 0) {
return Array.from({ length: this.plantillas.length }, (_, i) => i);
}
var templates = [];
temas.forEach(tema => {
console.log(tema);
if (this.temas.has(tema)) {
templates = templates.concat(this.temas.get(tema));
console.log(this.temas.get(tema));
}
else {
console.error(`The topic \'${tema}\' is not currently defined`);
throw new Error(`The topic \'${tema}\' is not currently defined`);
}
});
if (templates.length == 0) {
console.error(`No correct topics were passed`);
throw new Error(`No correct topics were passed`);
}
console.log(templates);
console.log([...new Set(templates)]);
return [...new Set(templates)];
}

}

module.exports = {
QuestionGenerator
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ cron.schedule(`*/${minutes} * * * *`, () => {
// Route for extracting countries
app.get('/extract', async (req, res) => {
try {
res.json(extractData());
res.json(await extractData());
} catch (error) {
res.status(500).json({ message: error.message })
// res.status(500).json({ error: 'Internal Server Error' });
Expand Down

0 comments on commit aad6f55

Please sign in to comment.