Bots de conversa de Telegram amb Google Apps Script

Bots de conversa Exemples Dades pràctiques   Recursos CITCEA
Google Apps Script Projectes Interacció   Inici

Generem un diagrama de columnes que es pot consultar per GET i per Telegram

En aquest exemple agafarem unes dades que tenim en un full de càlcul i generarem una imatge vectorial en forma de diagrama de columnes (barres verticals) amb els valors del full de càlcul. Amb la idea de fer un exemple senzill, hem suposat que el nostre full de càlcul sempre té les dades corresponents a set dies i que en la primera columna hi ha el nom del dia i a la segona el valor que li correspon; aquest valor sempre estarà entre 0 i 100 per fer el programa més fàcil. En un proper exemple treballarem amb un nombre variable de dades que tenen menys restriccions en el rang de valors.

La següent imatge mostra el contingut del full de càlcul en un moment donat:

Full de càlcul

El resultat que obtindrem serà el gràfic següent:

Gràfic

En el nostre cas podrem obtenir el gràfic de dues maneres. Una d'elles serà a l'executar l'script des del navegador (funció doGet) i obtindrem una pàgina web que contindrà el gràfic. L'altra serà accedint des de Telegram (funció doPost) i, en cas de fer servir la comanda /grafic, obtindrem una imatge del gràfic, creada a partir de la miniatura del PDF, i un enllaç per descarregar-lo en format PDF.

El programa és el següent:

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_carpeta = "^^Hlod5Y4qEsLF9HrIsE6oYQa32f6NHeo";  // Carpeta on guardarem el fitxer
// Definim els colors que sortiran al gràfic
var negre = "#000000";
var blau = "#0000FF";
var transparent = "null";
function doGet(e){
  var resp = grafic();  // Genera el gràfic
  var nomFitxer = "grafic";  // Nom del fitxer
  var fitxerNou = DriveApp.getFolderById(IdCarpeta).createFile(nomFitxer + ".svg",resp);  // Crea el fitxer
  var idFitxer = fitxerNou.getId();  // Identificador del fitxer
  var urlDescFitxer = fitxerNou.getDownloadUrl();  // Adreça per baixar el fitxer
  var urlFitxer = "https://drive.google.com/uc?export=view&id=" + idFitxer;  // URL per veure el fitxer
  // Generem el codi HTML de la pàgina
  var pagina = "<!DOCTYPE HTML>" + "\n";
  pagina = pagina + "<html>" + "\n";
  pagina = pagina + "<head>" + "\n";
  pagina = pagina + "<meta charset='UTF-8'>" + "\n";
  pagina = pagina + "</head>" + "\n";
  pagina = pagina + "<body>" + "\n";
  pagina = pagina + "<h1>Valors de la setmana passada</h1>" + "\n";
  pagina = pagina + resp + "\n";
  pagina = pagina + "</body>" + "\n";
  pagina = pagina + "</html>" + "\n";
  return HtmlService.createHtmlOutput(pagina);  // Envia la pàgina web
}
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 realitzat = false;
  if(text == '/grafic'){
    var resposta = "Estem preparant el gràfic. Espera un moment.";  // Enviem un text
    sendText(id,resposta);  // mentre es prepara el gràfic, ja que el procés és lent
    var resp = grafic();  // Crea el gràfic
    var nomFitxer = "grafic";  // Nom del fitxer
    var fitxerNou = DriveApp.getFolderById(IdCarpeta).createFile(nomFitxer + ".svg",resp);  // Crea el fitxer
    var idFitxer = fitxerNou.getId();  // Identificador del fitxer
    var urlDescFitxer = fitxerNou.getDownloadUrl();  // Enllaç per descarregar el fitxer
    // Enllaç per veure el fitxer al navegador
    var urlFitxer = "https://drive.google.com/uc?export=view&id=" + idFitxer;  
    var blob = UrlFetchApp.fetch(urlFitxer).getBlob();  // Agafa el gràfic en format binari
    var b64 = blob.getContentType() + ';base64,'+ Utilities.base64Encode(blob.getBytes());
    // Creem una pàgina web de mínims que serà la base del PDF
    var htmlEst = '<style type="text/css" media="print">@page {size: landscape;} </style>';
    var htmlInst = htmlEst + '<img src="data:' + b64 + '" width=900 alt="Histograma">';
    var html = HtmlService.createHtmlOutput(htmlInst);  // Crea la pàgina web
    // Crea el PDF
    var pdf = DriveApp.createFile(html.getAs("application/pdf").setName(nomFitxer + ".pdf"));
    var urlDescPDF = pdf.getDownloadUrl();  // Enllaç per descarregar el fitxer
    var pdfId = pdf.getId();  // Identificador del fitxer PDF
    var repetir = true;
    // Hem d'esperar que estigui llesta la miniatura
    var cnt = 0;  // Comptador de dècimes de segon
    while(repetir){  // Mentre no estigui
      var thumb = DriveApp.getFileById(pdfId).getThumbnail();  // Mirem si ja s'ha creat la miniatura
      Utilities.sleep(100);  // Esperem una dècima de segon
      cnt++;
      if((cnt > 100) || (thumb)){  // Si ja està o han passat deu segons
        repetir = false;  // Sortim del bucle
      }
    }
    // El títol conté l'enllaç
    var descrip = "Pots descarregar el PDF aquí: " + urlDescPDF;
    sendBlobFile(id,thumb,descrip);  // Enviem la imatge
    realitzat = true;
  }
  if (!realitzat){
    var resposta = "Comanda desconeguda";
    sendText(id,resposta);
  }
}
function grafic(){
  var sh = SpreadsheetApp.openById(ssId).getSheetByName("dades");  // Agafem el full
  var dades = sh.getDataRange().getValues();  // Agafem les dades
  var noms = new Array();  // Vector per guardar els noms de les barres
  var valors = new Array();  // Vector per guardar els valors de les barres
  for (var i in dades){  // Recorrem totes les dades
    if (i > 0){  // Ignorem la filera de títols
      var row = dades[i];  // Agafem una filera
      noms.push(row[0]);  // Nom de la barra
      valors.push(row[1]);  // Valor de la barra
    }
  }
  // Creem la capçalera
  var grafic =  cap(640, 480, "Capa 1")+ '\n';
  // Fem els eixos
  var zeroX = 50;
  var zeroY = 435;
  grafic = grafic + linia(zeroX-5, zeroY, 620, zeroY, 3, negre, "eixX") + '\n';
  grafic = grafic + linia(zeroX, 25, zeroX, 440, 3, negre, "eixY") + '\n';
  // Posem les divisions de l'eix Y
  for (var i = 0; i <= 10; i++){
    var ym = zeroY - 40 * i;
    var valor = 10 * i;
    var noml = 'm' + valor;
    var nomt = 'tm' + valor;
    grafic = grafic + linia(zeroX-5, ym, zeroX, ym, 2, negre, noml) + '\n';
    grafic = grafic + text(zeroX-10, ym+5, valor, 16, negre, "d", 0, 0, nomt) + '\n'; 
  } 
  // Posem els títols de l'eix X i les barres
  for (var i = 0; i < 7; i++){
    var xb = 95 + 80 * i;
    var alt = 4 * valors[i];
    var yb = zeroY - alt;
    var nomb = 'b' + i;
    var nomc = 'tc' + i;
    var nomv = 'tv' + i;
    grafic = grafic + rect(xb-25, yb, 50, alt, 0, blau, transparent, nomb) + '\n';
    grafic = grafic + text(xb, 450, noms[i], 16, negre, "c", 0, 0, nomc) + '\n'; 
    grafic = grafic + text(xb, yb-5, valors[i], 16, blau, "c", 1, 0, nomv) + '\n'; 
  } 
  // Posem el final del fitxer svg
  grafic = grafic + peu(); 
  return grafic;
}
function linia(xi, yi, xf, yf, gruix, color, ident){
  var resp = '<line id="' + ident + '" x1="' + xi + '" y1="' + yi + '" x2="' + xf + '" y2="' + yf;
  resp = resp + '" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="';
  resp = resp + gruix + '" stroke="' + color + '" fill="none"/>';
  return resp;
}
function rect(x, y, ample, alt, gruix, color, vora, ident){
  var resp = '<rect id="' + ident + '" x="' + x + '" y="' + y + '" width="' + ample + '" height="' + alt;
  resp = resp + '" stroke-width="' + gruix + '" stroke="' + vora + '" fill="' + color;
  resp = resp + '" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null"/>';
  return resp;
}
function text(x, y, txt, mida, color, alin, negreta, cursiva, ident){
  if (alin == "e"){  // Esquerra
    var aln = "start";
  }
  if (alin == "c"){  // Centre
    var aln = "middle";
  }
  if (alin == "d"){  // Dreta
    var aln = "end";
  }
  var resp = '<text id="' + ident + '" xml:space="preserve" text-anchor="' + aln;
  resp = resp + '" font-family="serif" font-size="' + mida + '" x="' + x + '" y="' + y +'"'; 
  if (negreta == 1){
    resp = resp + ' font-weight="bold"';
  }
  if (cursiva == 1){
    resp = resp + ' font-style="italic"';
  }
  resp = resp + ' stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="0" stroke="';
  resp = resp + color + '" fill="' + color + '">' + txt + '</text>';
  return resp;
}
function cap(ample, alt, titol){
  var resp = '<svg width="' + ample + '" height="' + alt;
  resp = resp + '" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"';
  resp = resp + ' xmlns:xlink="http://www.w3.org/1999/xlink">' + '\n';
  resp = resp + '<g>' + '\n' + '<title>' + titol + '</title>';
  return resp;
}
function peu(){
  var resp = '</g>' + '\n' + '</svg>';
  return resp;
}
function sendText(chatId,text_env,keyBoard){  // Funció que envia 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 sendBlobFile(chatId,blob_data,caption){
  var payload = {
    method: "sendPhoto",
    chat_id: String(chatId),
    photo: blob_data,
    caption: caption,
    parse_mode: "HTML"
  };
  var options = {
    method: "POST",
    payload: payload,
    muteHttpExceptions: true
  };
  UrlFetchApp.fetch( telegramUrl + '/', options);
}

 

 

 

 

 

 

 

 

 

 

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