| Bots de conversa | Exemples | Dades pràctiques | Recursos CITCEA | |
| Google Apps Script | Projectes | Interacció | Inici |
Aquest bot de Telegram permet crear un currículum i simular una entrevista de feina. Per a l'entrada del currículum, el bot va preguntant les diferents informacions que després formaran part del document PDF generat. En el mode d'entrevista, l'usuari ha de respoondre un test de diverses preguntes i es calcula una puntuació a partir de les respostes.
La informació entrada pels usuaris es guarda en un full de càlcul. Hi ha un document de Google que fa de plantilla; sobre una còpia d'aquest és on es posarà la informació introduïda per l'usuari per així generar el currículum.
El programa de l'script és el següent:
var token = "^^33169381:AAHcCfJ6yr9wlwRBSge347FEZo-97mLFt8k";
var telegramUrl = "https://api.telegram.org/bot" + token;
var spreadsheetId = "^^2LSz3xGeK7Ft7fA8otvN_ZXX1Bl9ItarKBX3y7cV9E";
var respostes = new Array(14);
var hoja = SpreadsheetApp.openById(spreadsheetId).getSheetByName('Hoja1'); // Abre la hoja de cálculo
var rango = hoja.getRange(1, 3, 1, hoja.getLastColumn()-2); // Obtiene el rango de la primera fila
var pf = rango.getValues()[0]; // Obtiene los valores de la primera fila como un array
var cv = [null,null,'Tu nombre', 'Quan vas neixer', 'País de naixement','Tu calle, 123','Ciutat',
'000 000 000','no_reply@example.com','Com ets','Que idiomas hablas','Titols que poseeixes',
'Experiencia laboral','Noms projectes','Logros hechos','Vull'];
var titols = { "Quan vas neixer": "Edat:", "País de naixement": "Nacionalitat:",
"Experiencia laboral": "EXPERIENCIA", "Titols que poseeixes":"FORMACIÓ",
"Noms projectes": "PROJECTES","Vull":"MÉS SOBRE MI","Com ets":"APTITUDS",
"Logros hechos":"ASSOLIMENTS", "Que idiomas hablas":"IDIOMES"};
var docId = '^^-5mFe3LLiam0OUZUtkfi_feorN1w_c05KqAyEHWvMY';
var contador= 0;
var preguntas = new Array(12);
var tt = "Què faries per incentivar la creativitat en el teu equip durant la fase de disseny d'un projecte?\n";
tt = tt + "A) Proporcionar temps addicional per desenvolupar idees fora del convencional.\n";
tt = tt + "B) Evitar idees fora de la indústria per enfocar-se només en les solucions provades.\n";
tt = tt + "C) Fixar objectius molt específics per evitar distraccions.\n";
tt = tt + "D) Evitar l'ús d'eines digitals per centrar-se únicament en el tradicional.";
preguntas[0] = tt;
tt = "Com abordaries la integració d'un nou membre a l'equip enmig d'un projecte ja avançat?\n";
tt = tt + "A) Reassignar el nou membre a un equip diferent.\n";
tt = tt + "B) Involucrar-lo en una part petita del projecte perquè conegui l'equip.\n";
tt = tt + "C) Donar-li un rol important immediatament perquè aprengui amb la pràctica.\n";
tt = tt + "D) Deixar que s'integri pel seu compte sense guiar-lo.";
preguntas[1] = tt;
tt = "Un membre de l'equip té una proposta que no ha estat provada abans a l'empresa. Com actuaries?\n";
tt = tt + "A) Descarta la proposta ja que és un risc.\n";
tt = tt + "B) Analitzar la seva viabilitat i si és prometedora, provar-la en una escala petita.\n";
tt = tt + "C) Esperar que altres equips avaluïn la proposta primer.\n";
tt = tt + "D) Realitzar una anàlisi detallada per trobar errors en la proposta.";
preguntas[2] = tt;
tt = "Com gestionaries la comunicació entre el teu equip durant un projecte complex?\n";
tt = tt + "A) Utilitzar una plataforma en línia perquè tots els membres comparteixin ";
tt = tt + "actualitzacions i progressos.\n";
tt = tt + "B) Organitzar reunions diàries en persona perquè tots estiguin al corrent.\n";
tt = tt + "C) Deixar que cada membre triï la forma de comunicació que prefereixi.\n";
tt = tt + "D) Demanar a cada membre que informi directament al líder del projecte sense comunicar-se ";
tt = tt + "amb els altres.";
preguntas[3] = tt;
tt = "Com animaries el teu equip perquè prengui la iniciativa en els seus rols individuals?\n";
tt = tt + "A) Establir objectius clars però permetre flexibilitat en el seu enfocament.\n";
tt = tt + "B) Insistir que tots segueixin un protocol rígid per evitar errors.\n";
tt = tt + "C) Recompensar només els que compleixin objectius específics.\n";
tt = tt + "D) Evitar reconèixer públicament les iniciatives individuals per no generar competència.";
preguntas[4] = tt;
tt = "Com respondries si un projecte crític té un retard considerable?\n";
tt = tt + "A) Buscar una solució ràpida amb una empresa externa.\n";
tt = tt + "B) Motivar el teu equip perquè proposin solucions col·lectives.\n",
tt = tt + "C) Ignorar el retard i centrar-se en la següent etapa.\n";
tt = tt + "D) Delegar el problema a un altre departament.";
preguntas[5] = tt;
tt = "Quina estratègia utilitzaries per assegurar-te que els rols dins de l'equip estan equilibrats ";
tt = tt + "i són manejables?\n";
tt = tt + "A) Revisar periòdicament la càrrega de treball amb l'equip.\n";
tt = tt + "B) Distribuir més treball entre els membres més productius.\n";
tt = tt + "C) No realitzar cap ajust perquè cada membre gestioni la seva pròpia càrrega.\n";
tt = tt + "D) Reassignar tasques segons el rang jeràrquic de cada membre.";
preguntas[6] = tt;
tt = "El teu equip troba un problema tècnic que pot requerir un redisseny. Com procediries?\n";
tt = tt + "A) Informar immediatament a la direcció sense considerar solucions alternatives.\n";
tt = tt + "B) Avaluar ràpidament el problema per proposar solucions creatives.\n";
tt = tt + "C) Aturar tot el projecte fins que es resolgui el problema.\n";
tt = tt + "D) Reassignar el problema a un equip de suport extern.";
preguntas[7] = tt;
tt = "Com afrontaries un conflicte entre dos membres clau de l'equip?\n";
tt = tt + "A) Demanar-los que resolguin el problema sense intervenció.\n";
tt = tt + "B) Involucrar-te directament i mediar per trobar un compromís.\n";
tt = tt + "C) Reassignar un dels membres a un altre equip per evitar més conflictes.\n";
tt = tt + "D) Ignorar el conflicte fins que sigui un problema greu.";
preguntas[8] = tt;
tt = "Com fomentaries la innovació a llarg termini en un entorn competitiu?\n";
tt = tt + "A) Establir un programa de desenvolupament professional continu per al teu equip.\n";
tt = tt + "B) Sol·licitar idees innovadores però sense donar-los seguiment regular.\n";
tt = tt + "C) Centrar-se únicament en la innovació en els productes existents.\n";
tt = tt + "D) Evitar prendre riscos per mantenir l'estabilitat actual.";
preguntas[9] = tt;
tt = "Com fomentaries la creativitat en un projecte on les restriccions pressupostàries són una limitació?\n";
tt = tt + "A) Limitar la cerca de solucions al que s'ha provat prèviament.\n";
tt = tt + "B) Permetre que l'equip proposi idees de baix cost i les revisi col·lectivament.\n";
tt = tt + "C) Delegar la responsabilitat creativa únicament a un líder.\n";
tt = tt + "D) Centrar-se només en opcions que compleixin amb un pressupost específic.";
preguntas[10] = tt;
tt = "Quina estratègia implementaries per impulsar la presa d'iniciativa entre els membres del teu equip ";
tt = tt + "durant l'execució d'un projecte?\n";
tt = tt + "A) Oferir als membres un espai per suggerir millores en les seves àrees.\n";
tt = tt + "B) Oferir incentius només a aquells que es destaquin en el compliment d'objectius específics.\n";
tt = tt + "C) Supervisar estrictament les activitats per garantir l'adherència als objectius.\n";
tt = tt + "D) Desincentivar la iniciativa per evitar possibles errors.";
preguntas[11] = tt;
var respostes = [["A","B","C","D"],["A","B","C","D"],["A","B","C","D"],["A","B","C","D"],
["A","B","C","D"],["A","B","C","D"],["A","B","C","D"],["A","B","C","D"],
["A","B","C","D"],["A","B","C","D"],["A","B","C","D"],["A","B","C","D"]];
var puntuacio = [[5,0,1,0],[0,5,2,0],[0,5,2,1],[4,5,2,0],[5,0,2,0],[2,5,0,1],
[5,2,0,1],[1,5,0,2],[0,5,1,0],[5,2,1,0],[0,5,1,2],[5,2,0,0]];
function doPost(e) {
var data = JSON.parse(e.postData.contents);
if (data.message) {
var text = data.message.text;
var id = data.message.chat.id;
var id_usuari = data.message.from.id;
var id_missatge = data.message.message_id;
var lang = data.message.from.language_code;
var nom_usr = data.message.from.first_name;
var location = data.message.location;
var spreadsheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Hoja1");
if (text.indexOf("/") == 0) {
if(text == '/cv'){ // Iniciar curriculum
iniParam(id);
}
if(text == '/start'){
var resposta = "Comandes disponibles:\n";
resposta = resposta + "/cv Amb aquesta comanda es crea el curriculum.\n";
resposta = resposta + "/sim Amb aquesta comanda s'inicia una simulació d'entrevista ";
resposta = resposta + "de treball per ser enginyer mecànic.";
sendText(id,resposta);
}
if (text == '/sim') {
var inde = 0;
var puntuacion = 0;
PropertiesService.getScriptProperties().setProperty('inde', inde);
PropertiesService.getScriptProperties().setProperty('puntuacion', puntuacion);
pregunt(id, inde);
}
} else {
param(id, text);
}
} else if (data.callback_query) {
var id = data.callback_query.message.chat.id;
var callbackData = data.callback_query.data;
var id_usuari = data.callback_query.from.id;
handleCallbackQuery(id, callbackData, id_usuari);
}
}
function subs(id_usr){
var sh = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Hoja1"); // Obrim el full de càlcul
var dades = sh.getDataRange().getValues(); // Agafem el contingut
var dar_fil = sh.getLastRow(); // Índex de la darrera filera
var dar_col= sh.getLastColumn(); //Índex darrera columna
var template = DriveApp.getFileById(docId); //Agafem la plantilla de currículum
// Mirem si l'usuari consta a la llista
for(var i = 0; i < dar_fil; i++){ // Mirem totes les dades
var row = dades[i]; // Agafa una filera
var num_usuari = row[0]; // Agafa el número d'usuari de la filera
if(num_usuari == id_usr){ // Mira si és l'usuari actual
// Crear una copia amb un nom únic (row[2] és el nom de l'usuari)
var copiedFile = template.makeCopy('Currículum_' + row[2].replace('^',''));
var doc = DocumentApp.openById(copiedFile.getId()); //Obrim la copia
var body = doc.getBody(); //Entrem al cos del document
for(var e=2; e < dar_col-1; e++){ //Recorrem cada columna
row[e] = row[e].replace("^","");
if (row[e] == "."){
if (cv[e] in titols){
body.replaceText(titols[cv[e]],'').replaceText(cv[e], '');
} else {
body.replaceText(cv[e],'');
}
} else {
// Reemplaza 'texto' por la respuesta del usuario en todo el documento
body.replaceText(cv[e], row[e]);
}
}
}
}
doc.saveAndClose();
var tt = "Moltes felicitats! Ja has completat el formulari, a continuació t'enviem ";
tt = tt + "el curriculum en format pdf. Aquesta acció pot tardar uns segons.";
sendText(id_usr,tt);
// Fem un bucle per esperar que estigui llest el pdf
var repetir = true;
var cnt = 0; // Comptador de dècimes de segon
while(repetir){ // Mentre no estigui
// Mirem si ja s'ha creat el pdf
var pdf = DriveApp.getFileById(copiedFile.getId()).getAs('application/pdf');
Utilities.sleep(10000); // Esperem una dècima de segon
cnt++;
if((cnt > 10000) || (pdf)){ // Si ja està o han passat deu segons
repetir = false; // Sortim del bucle
sendDocument(id_usr, pdf);
}
}
}
function param(id_usr, comand) {
// Processa els paràmetres
var userProperties = PropertiesService.getUserProperties();
var contador = parseInt(userProperties.getProperty('contador')) || 0;
var sh = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Hoja1");
// Obrim el full de càlcul
var dades = sh.getDataRange().getValues();
// Agafem el contingut
var dar_fil = sh.getLastRow();
// Índex de la darrera filera
// Mirem si l'usuari consta a la llista
var fila = 0;
for (var i = 0; i < dar_fil; i++) {
// Mirem totes les dades
var row = dades[i];
// Agafa una filera
var num_usuari = row[0];
// Agafa el número d'usuari de la filera
if (num_usuari == id_usr) {
// Mira si és l'usuari actual
fila = i;
// No sumem 1 perquè al vector es compta a partir de 0
}
}
var row = dades[fila];
// Agafem les dades de l'usuari
var row0 = dades[0].slice(2, 16);
// Agafem les preguntes
var row1 = dades[1].slice(2, 16);
// Agafem estat d'edició
var rowi = row.slice(2, 16);
// A la segona casella tenim l'estat de l'enviament de paràmetres
var estat = row[1];
if (estat < 14) {
// Si encara no hem rebut tots els paràmetres
var rang = sh.getRange(fila + 1, 2);
// Selecciona la casella de l'estat
rang.setValue(estat + 1);
// Passem a l'estat següent
var rang = sh.getRange(fila + 1, estat + 3);
// Selecciona la casella següent
// Posem ^ al davant perquè ho interpreti com a text
rang.setValue('^' + comand);
// Guarda el valor a la casella
}
if (estat == 14) {
// Si ja tenim tots els paràmetres, comencem el procès d'edició
if (comand.toLowerCase() == "si") {
editar(id_usr, rowi);
contador += 2;
userProperties.setProperty('contador', contador);
return;
}
if (comand.toLowerCase() == "no") {
subs(id_usr);
}
if (comand== "cancelar"){
subs(id_usr);
}
var editarNumero = parseInt(comand);
if (!isNaN(editarNumero) && editarNumero >= 1 && editarNumero <= rowi.length) {
var respostaEditar = rowi[editarNumero - 1];
var indexRes = editarNumero - 1;
sendText(id_usr, "Siusplau, escriu la nova resposta per '" + row0[editarNumero - 1] + "'." );
contador += 1;
userProperties.setProperty('contador', contador);
userProperties.setProperty('indexRes', indexRes);
return;
};
if (contador > 2) {
var savedIndexRes = userProperties.getProperty('indexRes');
var prova = parseInt(savedIndexRes);
actualitzarResposta(id_usr, comand, fila, prova + 2);
contador += 1
userProperties.setProperty('contador', contador);
}
if (contador > 3) {
subs(id_usr);
}
} else {
sendText(id_usr, pf[estat + 1]);
}
}
function editar(id_usr){
// Agregar una opción para cancelar
var missatge = "\nEscriu el número de la resposta que vols editar o 'cancelar' per sortir.";
sendText(id_usr, missatge);
}
function actualitzarResposta(id_usr,novaResposta ,fila,columna) {
// Actualizar la respuesta en el historial
var sh = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Hoja1");
var rang = sh.getRange(fila + 1, columna + 1); // +1 because getRange is 1-based
rang.setValue('^' + novaResposta);
// Actualizar el registro de respuestas del usuario
//dades[fila] = historialRespostes;
// Confirmar la actualización al usuario
sendText(id_usr, "La resposta ha sigut actualitzada correctament.");
}
function iniParam(id_usr){ // Es prepara per rebre paràmetres
var sh = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Hoja1"); // Agafa el full de càlcul
var dades = sh.getDataRange().getValues(); // Agafa els valors
var dar_fil = sh.getLastRow(); // Índex de la darrera filera
// Mirem si l'usuari ja consta a la llista
var fila = 0;
for(var i = 0; i < dar_fil; i++){ // Recorrem les dades
var row = dades[i]; // Llegim una filera
var num_usuari = row[0]; // Identificador de l'usuari
if(num_usuari == id_usr){ // Si és el que correspon
fila = i + 1; // Cal sumar 1 perquè comença a comptar des d'1
}
}
// Si l'usuari és nou el donarem d'alta
// Si no és nou, esborrarem les dades perquè entenem que vol tornar a començar
var camps = new Array(16); // Contindrà els valors per guardar a la taula
camps[0] = id_usr; // Identificador de l'usuari
camps[1] = 0; // Encara no tenim cap paràmetre
for(var i = 2; i < 16; i++){
camps[i] = ""; // No hi ha paràmetres
}
var valu = new Array(1); // Matriu de dades a escriure
valu[0] = camps; // Converteix el vector en una matriu d'una filera i dues columnes
if(fila == 0){ // Si l'usuari és nou
sh.appendRow(camps); // Afegeix una filera amb les dades
} else { // Si no és nou, sobrescrivim
// La funció getRange ens permet seleccionar el grup de caselles sobre les que anem a escriure
// El primer paràmetre és la filera on comença el grup, en el nostre cas la que hem trobat abans
// El segon paràmetre és la columna on comença el grup, en el nostre exemple la primera (comencen en 1)
// El tercer paràmetre és el nombre de fileres que tindrà el grup, per a nosaltres una
// El quart paràmetre és el nombre de columnes que ocupa el grup, en el nostre cas set
var rang = sh.getRange(fila, 1, 1, 16);
rang.setValues(valu); // Guarda els valors a les caselles, substituïnt els anteriors
}
//Reinciem el comptador
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('contador', 0);
var resposta = "Iniciem la creació del curriculum.\nPer passar a la següent ";
resposta = resposta + "pregunta i deixar la actual en blanc escriu un punt";
sendText(id_usr,resposta);
sendText(id_usr,pf[0]);
}
function fiParam(id_usr,fila){ // Acaba el procés de recepció de paràmetres
var sh = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Hoja1"); // Obre el full de càlcul
// Tornem l'usuari a l'estat inicial
var camps = new Array(16); // Contindrà els valors per guardar a la taula
camps[0] = id_usr; // Identificador de l'usuari
camps[1] = 0; // Encara no tenim cap paràmetre
for(var i = 2; i < 16; i++){
camps[i] = "";
}
var valu = new Array(1); // Matriu de dades a escriure
valu[0] = camps; // Converteix el vector en una matriu d'una filera i dues columnes
var rang = sh.getRange(fila+1, 1, 1, 16);
rang.setValues(valu); // Guarda els valors a les caselles, substituïnt els anteriors
}
function sendText(chatId,text_env,keyBoard){ // Funció que prepara per enviar un text o un teclat a Telegram
keyBoard = keyBoard || 0;
if(keyBoard.inline_keyboard || keyBoard.keyboard){
var data = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(chatId),
text: text_env,
parse_mode: "HTML",
reply_markup: JSON.stringify(keyBoard)
}
}
} else {
var data = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(chatId),
text: text_env,
parse_mode: "HTML"
}
}
}
UrlFetchApp.fetch( telegramUrl + '/', data);
}
function sendDocument(chatId, documentBlob) {
var data = {
method: "post",
payload: {
method: "sendDocument",
chat_id: String(chatId),
document: documentBlob
}
};
UrlFetchApp.fetch(telegramUrl + '/', data);
}
function pregunt(id, inde) {
var tecles = {
"inline_keyboard": [
[{"text": respostes[inde][0], "callback_data": "sol1-" + inde },
{"text": respostes[inde][1], "callback_data": "sol2-" + inde },
{"text": respostes[inde][2], "callback_data": "sol3-" + inde },
{"text": respostes[inde][3], "callback_data": "sol4-" + inde }]
]
};
var titol = preguntas[inde];
sendText(id, titol, tecles);
}
function handleCallbackQuery(id, callbackData, id_usuari) {
var inde = parseInt(PropertiesService.getScriptProperties().getProperty('inde'));
var puntuacion = parseInt(PropertiesService.getScriptProperties().getProperty('puntuacion'));
var respuestaIndex = parseInt(callbackData.split("-")[0].replace('sol', ''));
puntuacion += puntuacio[inde][respuestaIndex - 1];
inde += 1;
if (inde < preguntas.length) {
PropertiesService.getScriptProperties().setProperty('inde', inde);
PropertiesService.getScriptProperties().setProperty('puntuacion', puntuacion);
pregunt(id, inde);
} else {
var tt = "Aquest test es una simulació d'una entrevista de trabal per un enginyer ";
tt = tt + "mecànic. Per aquest tipus d'entrevistes es valoren principalment aquestes ";
tt = tt + "4 aptituts: creativitat, treball en equip, iniciativa i gestió de projectes. ";
tt = tt + "Per aquesta raó en aquest test es valoren principalmente aquestes qualitats.\n\n ";
tt = tt + "Has obtingut una puntuació total de " + redondearAPeriodico(puntuacion/6,2) + " sobre 10."
sendText(id, tt);
}
}
function redondearAPeriodico(num, decimales) {
var factor = Math.pow(10, decimales);
return Math.round(num * factor) / factor;
}

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.