| Bots de conversa | Exemples | Dades pràctiques | Recursos CITCEA | |
| Google Apps Script | Projectes | Interacció | Inici |
En aquest exemple agafarem un document plantilla que tenim a Google Drive, en farem una còpia que personalitzarem amb les dades de l'usuari que ho sol·liciti (mantenint intacta la plantilla). Un cop creat el document personalitzat, el passarem a PDF i el posarem a disposició de l'usuari. Després esborrarem la versió personalitzada. Veurem tres maneres de posar-lo a disposició del sol·licitant. També veurem dues maneres de personalitzar el document. S'ha agafat l'Id de Telegram com a identificador de l'usuari perquè així tenim un identificador únic per usuari i, a més, evitem la necessitat de posar paràmetres a la comanda.
El document de la plantilla té una sèrie de camps que són els que es poden personalitzar. En el nostre cas hem posat tres paràmetres i hem situat el seu nom entre claus. Podem marcar els paràmetres com vulguem (en lloc de les claus) però ens hem d'assegurar que no apareixeran els paràmetres marcats en altres llocs del document. Els tres paràmetres del nostre exemple són:
| Paràmetre | Descripció |
| {nom} | Nom i cognoms de l'usuari |
| {hora} | Hora en la que s'ha fet l'activitat |
| {data} | Data en què s'ha fet el document i l'activitat |
També tindrem un full de càlcul amb les dades de cada un dels possibles usuaris. Les columnes del full són:
| Columna | Contingut |
| 0 | Id de Telegram de l'usuari |
| 1 | Nom i cognoms de la persona |
| 2 | Data en què s'ha fet el document i l'activitat |
| 3 | Hora en la que s'ha fet l'activitat |
| 4 | Adreça de correu electrònic de l'usuari |
Podem posar tants paràmetres com ens convingui. En alguns casos potser ens interessarà afegir camps, en altres potser separarem el nom i els cognoms en camps diferents, etc. Basant-nos en aquest exemple podem fer cartes, certificats d'assistència i altres documents personalitzats.
Aquest script fa servir només la comanda /cert però es podria ampliar amb més comandes que li permetessin fer altres funcions. Per exemple, es podria fer servir el mateix script per inscriure's a l'activitat de la qual després s'obté el certificat d'assistència.
La primera cosa que cal fer és crear el bot de conversa, després cal crear l'script per acabar assignant l'script al bot de conversa. Anem a veure com seria l'script.
Atenció: Si el PDF triga un cert temps a crear-se, ens podem trobar que quan el programa l'intenta enviar encara no estigui llest. Per evitar el problema, podem fer un bucle d'espera mentre es crea el document; com es fa en les línies marcades en color en el programa d'aquest exemple.
La funció doPost només mira quina és la comanda rebuda i, si és l'esperada, crida la funció que genera el document. El primer que fa la funció és buscar l'usuari a la taula. Si el troba, recopila totes les dades necessàries de la filera corresponent. Llavors envia un missatge a l'usuari on li indica que s'està preparant el document, aquest missatge és convenient perquè la creació del document triga alguns segons. En aquesta primera versió es crea un document provisional buit que acabarà contenint la versió personalitzada del document. Després es van copiant, un a un, els paràgrafs del document original (del que necessitem l'identificador) sobre el nou mentre es substitueix, si escau, el paràmetre pel seu valor. Hem d'entendre la paraula paràgraf en sentit ampli, és a dir un conjunt de text que forma una unitat tancada. Un cop acabat de crear el document personalitzat, en genera una versió PDF que guarda en la carpeta indicada (amb el seu identificador). Seguidament agafa les dades (adreça URL i identificador) del fitxer PDF i esborra el document provisional (l'envia a la paperera). Per acabar, envia un missatge a l'usuari per dir-li que el document ja està i donant-li l'enllaç per descarregar-lo.
var token = "^^34328844:AAFIpk-e7j3UZtYQYQaTduf4hEhnDqIcNXI"; // API Token de Telegram
var telegramUrl = "https://api.telegram.org/bot" + token; // URL que comunica el bot de conversa amb Telegram
var ssId = "^^ThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA"; // Identificador del full de càlcul
var id_plantilla = "1Di13cpVu3oY-AN7wdg-cPp8pmNqNmYTVh7FDkkq3cX8"; // Document que serveix de plantilla
var id_carpeta = "^^Hlod5Y4qEsLF9HrIsE6oYQa32f6NHeo"; // Carpeta on guardarem el PDF
var realitzat = false;
function doPost(e){
var data = JSON.parse(e.postData.contents); // Llegeix les dades rebudes per JSON i les guarda
var text = data.message.text; // Comanda enviada
var id = data.message.chat.id; // Identificador de la finestra d'on prové el missatge
var id_usuari = data.message.from.id; // Identificador de l'usuari
var id_missatge = data.message.message_id; // Identificador del missatge
var lang = data.message.from.language_code ; // Idioma de l'usuari
var nom_usr = data.message.from.first_name ; // Nom de l'usuari
var location = data.message.location; // Localització de l'usuari (si es sap)
var comanda = text.split("@"); // El signe @ separa la comanda dels paràmetres
var cmd = comanda[0]; // Comanda
var par = comanda[1]; // Paràmetre
if(cmd == '/cert'){
preparaCertif(id); // Preparem el certificat
realitzat = true;
}
if(!realitzat){
var resposta = "Comanda desconeguda";
sendText(id,resposta);
}
}
// El paràmetre usuari és el Id i serveix tant per buscar
// el certificat com per enviar la resposta
function preparaCertif(usuari){
var sh = SpreadsheetApp.openById(ssId).getSheetByName("examen"); // Obrim el full de càlcul
var dades = sh.getDataRange().getValues(); // Agafem els valors
var resposta = "";
// Primer busquem a quina fila estan les dades de l'usuari
// Si el resultat és 0 vol dir que no hi és
var fila = 0;
for(var i in dades){
var row = dades[i]; // Agafa una filera
var num_usuari = row[0]; // Id de l'usuari
if(num_usuari == usuari){
fila = i; // Aquesta és la filera corresponent a l'usuari
}
}
if(fila == 0){ // Si no l'hem trobat
resposta = "No tens dret al document demanat";
sendText(usuari,resposta);
} else {
resposta = "Estem preparant el document";
sendText(usuari,resposta);
var row = dades[fila]; // Agafa les dades
var num = row[0];
var nom = row[1];
var data = row[2];
var hora = row[3];
var correu = row[4];
var plantilla = DocumentApp.openById(id_plantilla); // Obrim la plantilla
var titol = "cert_" + num; // Posa un títol que inclou el número d'usuari, per poder saber de qui és
var doc_prov = DocumentApp.create(titol); // Crea el document provisional
var id_doc_prov = doc_prov.getId(); // N'obté l'identificador
var plantilla_paragrafs = plantilla.getBody().getParagraphs(); // Agafa el contingut de la plantilla
// Carreguem tots els paràgrafs de la Plantilla
for(var j = 0; j < plantilla_paragrafs.length; j++){ // Per a tots els paràgrafs del document
var parag = plantilla_paragrafs[j].copy(); // Guarda una còpia del paràgraf a la variable
parag = parag.replaceText("{nom}",nom); // Substitueix el nom
parag = parag.replaceText("{hora}",hora); // Substitueix l'hora
parag = parag.replaceText("{data}",data); // Substitueix la data
doc_prov.getBody().appendParagraph(parag); // Posa el paràgraf al nou document
}
doc_prov.saveAndClose(); // Guarda i tanca el document
// Genera el contingut PDF apartir del document Final de la combinació
var docblob = DriveApp.getFileById(id_doc_prov).getAs('application/pdf');
docblob.setName(titol + ".pdf"); // Posa el nom del fitxer
// Crea el fitxer PDF a partir del contingut guardat abans
var file = DriveApp.getFolderById(id_carpeta).createFile(docblob);
var url_fitxer = file.getDownloadUrl(); // Adreça per descarregar el PDF
var id_fitxer = file.getId(); // Identificador del document PDF
DriveApp.getFileById(id_doc_prov).setTrashed(true); // Marca com a esborrat el document provisional
resposta = "El document està llest, el pots descarregar a " + url_fitxer;
sendText(usuari,resposta);
}
}
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);
}
En la primera versió li donem a l'usuari un enllaç per descarregar el document. Una alternativa seria fer servir un botó de teclat en línia. En aquesta versió, a més, en lloc de generar el document personalitzat paràgraf a paràgraf el que farem serà copiar el document de la plantilla i modificar la còpia. Aquesta forma de crear el document és més eficient ja que triga, aproximadament, un segon menys en executar-se (en el cas del document que hem fet servir per provar-ho).
var token = "^^34328844:AAFIpk-e7j3UZtYQYQaTduf4hEhnDqIcNXI"; // API Token de Telegram
var telegramUrl = "https://api.telegram.org/bot" + token; // URL que comunica el bot de conversa amb Telegram
var ssId = "^^ThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA"; // Identificador del full de càlcul
var id_plantilla = "1Di13cpVu3oY-AN7wdg-cPp8pmNqNmYTVh7FDkkq3cX8"; // Document que serveix de plantilla
var id_carpeta = "^^Hlod5Y4qEsLF9HrIsE6oYQa32f6NHeo"; // Carpeta on guardarem el PDF
var realitzat = false;
function doPost(e){
var data = JSON.parse(e.postData.contents); // Llegeix les dades rebudes per JSON i les guarda
var text = data.message.text; // Comanda enviada
var id = data.message.chat.id; // Identificador de la finestra d'on prové el missatge
var id_usuari = data.message.from.id; // Identificador de l'usuari
var id_missatge = data.message.message_id; // Identificador del missatge
var lang = data.message.from.language_code ; // Idioma de l'usuari
var nom_usr = data.message.from.first_name ; // Nom de l'usuari
var location = data.message.location; // Localització de l'usuari (si es sap)
var comanda = text.split("@"); // El signe @ separa la comanda dels paràmetres
var cmd = comanda[0]; // Comanda
var par = comanda[1]; // Paràmetre
if(cmd == '/cert'){
preparaCertif(id);
realitzat = true;
}
if(!realitzat){
var resposta = "Comanda desconeguda";
sendText(id,resposta);
}
}
// El paràmetre usuari és el Id i serveix tant per buscar
// el certificat com per enviar la resposta
function preparaCertif(usuari){
var sh = SpreadsheetApp.openById(ssId).getSheetByName("examen"); // Obre el full de càlcul
var dades = sh.getDataRange().getValues(); // Agafa el contingut
var resposta = "";
// Primer busquem a quina fila estan les dades de l'usuari
// Si el resultat és 0 vol dir que no hi és
var fila = 0;
for(var i in dades){ // Recorre totes les dades
var row = dades[i]; // Agafa una filera
var num_usuari = row[0]; // Identificador de l'usuari
if(num_usuari == usuari){
fila = i; // Aquesta és la filera de l'usuari
}
}
if(fila == 0){ // Si no l'hem trobat
resposta = "No tens dret al document demanat";
sendText(usuari,resposta);
} else {
resposta = "Estem preparant el document";
sendText(usuari,resposta);
var row = dades[fila]; // Agafa la filera
var num = row[0];
var nom = row[1];
var data = row[2];
var hora = row[3];
var correu = row[4];
var plantilla = DriveApp.getFileById(id_plantilla); // Agafa la plantilla
var titol = "cert_" + num; // Posa un títol que inclou el número d'usuari, per poder saber de qui és
var doc_prov = plantilla.makeCopy(titol); // Creem la còpia de la plantilla
var id_doc_prov = doc_prov.getId(); // Agafem l'identificador del document creat
var document = DocumentApp.openById(id_doc_prov); // Obrim la plantilla
var contingut = document.getBody(); // Agafem el contingut del document
contingut.replaceText("{nom}",nom); // Substitueix el nom
contingut.replaceText("{hora}",hora); // Substitueix l'hora
contingut.replaceText("{data}",data); // Substitueix la data
document.saveAndClose(); // Guarda i tanca el document
// Genera el contingut PDF apartir del document Final de la combinació
var docblob = DriveApp.getFileById(id_doc_prov).getAs('application/pdf');
docblob.setName(titol + ".pdf"); // Posa el nom al document PDF
// Crea el fitxer PDF a partir del contingut guardat abans
var file = DriveApp.getFolderById(id_carpeta).createFile(docblob);
var url_fitxer = file.getDownloadUrl(); // Adreça per baixar el fitxer
var id_fitxer = file.getId(); // Identificador del fitxer
DriveApp.getFileById(id_doc_prov).setTrashed(true);
// Creem el teclat amb la tecla per baixar-lo
var tecles = {"inline_keyboard":[ [{"text":"Descarrega","url":url_fitxer}] ]};
var titol = "El document està llest"; // Títol del teclat
sendText(usuari,titol,tecles);
}
}
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);
}
En aquesta versió el document s'envia per correu electrònic com a arxiu adjunt.
var token = "^^34328844:AAFIpk-e7j3UZtYQYQaTduf4hEhnDqIcNXI"; // API Token de Telegram
var telegramUrl = "https://api.telegram.org/bot" + token; // URL que comunica el bot de conversa amb Telegram
var ssId = "^^ThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA"; // Identificador del full de càlcul
var id_plantilla = "1Di13cpVu3oY-AN7wdg-cPp8pmNqNmYTVh7FDkkq3cX8"; // Document que serveix de plantilla
var id_carpeta = "^^Hlod5Y4qEsLF9HrIsE6oYQa32f6NHeo"; // Carpeta on guardarem el PDF
var realitzat = false;
function doPost(e){
var data = JSON.parse(e.postData.contents); // Llegeix les dades rebudes per JSON i les guarda
var text = data.message.text; // Comanda enviada
var id = data.message.chat.id; // Identificador de la finestra d'on prové el missatge
var id_usuari = data.message.from.id; // Identificador de l'usuari
var id_missatge = data.message.message_id; // Identificador del missatge
var lang = data.message.from.language_code ; // Idioma de l'usuari
var nom_usr = data.message.from.first_name ; // Nom de l'usuari
var location = data.message.location; // Localització de l'usuari (si es sap)
var comanda = text.split("@"); // El signe @ separa la comanda dels paràmetres
var cmd = comanda[0]; // Comanda
var par = comanda[1]; // Paràmetre
if(cmd == '/cert'){
preparaCertif(id); // Generem el document
realitzat = true;
}
if(!realitzat){
var resposta = "Comanda desconeguda";
sendText(id,resposta);
}
}
// El paràmetre usuari és el Id i serveix tant per buscar
// el certificat com per enviar la resposta
function preparaCertif(usuari){
var sh = SpreadsheetApp.openById(ssId).getSheetByName("examen"); // Obre el full de càlcul
var dades = sh.getDataRange().getValues(); // Agafa el contingut
var resposta = "";
// Primer busquem a quina fila estan les dades de l'usuari
// Si el resultat és 0 vol dir que no hi és
var fila = 0;
for(var i in dades){ // Recorre totes les dades
var row = dades[i]; // Agafa una filera
var num_usuari = row[0]; // Identificador de l'usuari
if(num_usuari == usuari){
fila = i; // Aquesta és la filera que correspon a l'usuari
}
}
if(fila == 0){ // Si no l'hem trobat
resposta = "No tens dret al document demanat";
sendText(usuari,resposta);
} else {
resposta = "Estem preparant el document";
sendText(usuari,resposta);
var row = dades[fila]; // Agafa les dades de l'usuari
var num = row[0];
var nom = row[1];
var data = row[2];
var hora = row[3];
var correu = row[4];
var plantilla = DriveApp.getFileById(id_plantilla); // Agafa el document de la plantilla
var titol = "cert_" + num; // Posa un títol que inclou el número d'usuari, per poder saber de qui és
var doc_prov = plantilla.makeCopy(titol); // Fa una còpia de la plantilla
var id_doc_prov = doc_prov.getId(); // Identificador del document
var document = DocumentApp.openById(id_doc_prov); // Obrim el document
var contingut = document.getBody(); // Agafem el contingut del document
contingut.replaceText("{nom}",nom); // Substitueix el nom
contingut.replaceText("{hora}",hora); // Substitueix l'hora
contingut.replaceText("{data}",data); // Substitueix la data
document.saveAndClose(); // Guarda i tanca el document
// Genera el contingut PDF apartir del document Final de la combinació
var docblob = DriveApp.getFileById(id_doc_prov).getAs('application/pdf');
docblob.setName(titol + ".pdf"); // Posa el nom al fitxer PDF
// Crea el fitxer PDF a partir del contingut guardat abans
var file = DriveApp.getFolderById(id_carpeta).createFile(docblob);
var url_fitxer = file.getDownloadUrl(); // Adreça per descarregar el PDF
var id_fitxer = file.getId(); // Identificador del fitxer PDF
DriveApp.getFileById(id_doc_prov).setTrashed(true); // Marca com esborrat el document provisional
var destinatari = correu; // Agafa l'adreça a la que l'hem d'enviar
// Aquest és el nom del remitent,
// l'adreça és la del compte de Google amb el que hem creat l'script
var remitent = "Generador automàtic de documents";
var titol = "El teu certificat";
var text = "Adjunt trobaràs el document sol·licitat.";
var adjunt = DriveApp.getFileById(id_fitxer); // Agafa el fitxer
MailApp.sendEmail(destinatari, titol, text, {
name: remitent,
attachments: [adjunt.getAs(MimeType.PDF)]
}); // Envia el correu
resposta = "T'hem enviat el document per correu electrònic";
sendText(usuari,resposta);
}
}
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);
}
En aquesta versió podríem esborrar el PDF (enviar-lo a la paperera) un cop ja l'hem enviat a l'usuari. En les primeres versions també podríem fer que l'usuari ens avisés (amb una comanda o amb un botó) quan hagués descarregat el document per poder-lo esborrar.

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