Создание презентаций Google Slides на основе больших данных в Node.js

Создание презентаций Google Slides на основе больших данных в Node.js

О практической работе

subjectПоследнее обновление: апр. 4, 2024
account_circleАвторы: timmerman

1. Обзор

В этой лаборатории вы узнаете, как использовать Google Slides в качестве специального инструмента для презентаций для анализа наиболее распространенных лицензий на программное обеспечение. Вы будете запрашивать весь открытый исходный код на GitHub с помощью API BigQuery и создавать набор слайдов с помощью API Google Slides для представления своих результатов. Пример приложения создан с использованием Node.js, но одни и те же основные принципы применимы к любой архитектуре.

Что вы узнаете

  • Создание презентаций с использованием Slides API
  • Использование BigQuery для получения информации о большом наборе данных
  • Копирование файла с помощью Google Drive API

Что вам понадобится

  • Node.js установлен
  • Доступ к Интернету и веб-браузеру
  • Аккаунт Google
  • Проект облачной платформы Google

2. Получить пример кода

Вы можете загрузить весь пример кода на свой компьютер...

…или клонируйте репозиторий GitHub из командной строки.

git clone https://github.com/googleworkspace/slides-api.git

Репозиторий содержит набор каталогов, представляющих каждый этап процесса, на случай, если вам понадобится ссылка на рабочую версию.

Вы будете работать с копией, расположенной в start каталоге, но при необходимости вы можете обращаться к остальным или копировать файлы из них.

3. Запустите пример приложения

Во-первых, давайте запустим и запустим сценарий Node. После загрузки кода следуйте инструкциям ниже, чтобы установить и запустить приложение Node.js:

  1. Откройте терминал командной строки на своем компьютере и перейдите в start каталог codelab.
  2. Введите следующую команду, чтобы установить зависимости Node.js.
npm install
  1. Введите следующую команду для запуска сценария:
node .
  1. Обратите внимание на приветствие, в котором показаны шаги этого проекта.
-- Start generating slides. --
TODO
: Get Client Secrets
TODO
: Authorize
TODO
: Get Data from BigQuery
TODO
: Create Slides
TODO
: Open Slides
-- Finished generating slides. --

Вы можете увидеть наш список TODO в slides.js , license.js и auth.js Обратите внимание, что мы используем обещания JavaScript для объединения шагов, необходимых для завершения приложения, поскольку каждый шаг зависит от завершения предыдущего шага.

Если вы не знакомы с промисами, не волнуйтесь, мы предоставим весь необходимый вам код. Короче говоря, промисы дают нам возможность обрабатывать асинхронную обработку более синхронно.

4. Получить секреты клиента

Чтобы использовать API-интерфейсы Slides, Bigquery и Drive, мы создадим клиент OAuth и учетную запись службы.

Настройка консоли разработчиков Google

  1. Используйте этот мастер , чтобы создать или выбрать проект в консоли разработчиков Google и автоматически включить API. Нажмите «Продолжить» , затем «Перейти к учетным данным» .
  2. На странице «Добавить учетные данные в проект» нажмите кнопку «Отмена» .
  3. В верхней части страницы выберите вкладку экрана согласия OAuth . Выберите адрес электронной почты , введите название продукта Slides API Codelab и нажмите кнопку «Сохранить» .

Включите API BigQuery, Drive и Slides.

  1. Выберите вкладку «Панель мониторинга» , нажмите кнопку «Включить API» и включите следующие 3 API:
  2. API BigQuery
  3. API Google Диска
  4. API Google Слайдов

Скачать секрет клиента OAuth (для слайдов и диска)

  1. Выберите вкладку «Учетные данные» , нажмите кнопку «Создать учетные данные» и выберите идентификатор клиента OAuth .
  2. Выберите тип приложения «Другое» , введите имя Google Slides API Codelab и нажмите кнопку «Создать» . Нажмите «ОК» , чтобы закрыть появившееся диалоговое окно.
  3. Нажмите кнопку file_download (Загрузить JSON) справа от идентификатора клиента.
  4. Переименуйте секретный файл в client_secret.json и скопируйте его в каталоги start/ и Finish/ .

Скачать секрет сервисного аккаунта (для BigQuery)

  1. Выберите вкладку «Учетные данные» , нажмите кнопку «Создать учетные данные» и выберите « Ключ учетной записи службы» .
  2. В раскрывающемся списке выберите «Новая учетная запись службы» . Выберите имя Slides API Codelab Service для своего сервиса. Затем нажмите «Роль» , прокрутите до BigQuery и выберите «Просмотр данных BigQuery» и «Пользователь задания BigQuery» .
  3. В качестве типа ключа выберите JSON .
  4. Нажмите Создать . Ключевой файл будет автоматически загружен на ваш компьютер. Нажмите «Закрыть» , чтобы выйти из появившегося диалогового окна.
  5. Переименуйте секретный файл в service_account_secret.json и скопируйте его в каталоги start/ и Finish/ .

Получить секреты клиента

В start/auth.js заполним метод getClientSecrets .

авторизация.js

const fs = require('fs');

/**
 * Loads client secrets from a local file.
 * @return {Promise} A promise to return the secrets.
 */

module.exports.getClientSecrets = () => {
 
return new Promise((resolve, reject) => {
    fs
.readFile('client_secret.json', (err, content) => {
     
if (err) return reject('Error loading client secret file: ' + err);
      console
.log('loaded secrets...');
      resolve
(JSON.parse(content));
   
});
 
});
}

Теперь мы загрузили секреты клиента. Учетные данные будут переданы следующему обещанию. Запустите проект с помощью node . чтобы убедиться в отсутствии ошибок.

5. Создайте клиент OAuth2

Чтобы создать слайды, давайте добавим аутентификацию в API Google, добавив следующий код в наш файл auth.js. Эта аутентификация запросит доступ к вашей учетной записи Google для чтения и записи файлов на Google Диске, создания презентаций в Google Slides и выполнения запросов только для чтения из Google BigQuery. (Примечание: мы не меняли getClientSecrets )

авторизация.js

const fs = require('fs');
const readline = require('readline');
const openurl = require('openurl');
const googleAuth = require('google-auth-library');
const TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
      process
.env.USERPROFILE) + '/.credentials/';
const TOKEN_PATH = TOKEN_DIR + 'slides.googleapis.com-nodejs-quickstart.json';

// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/slides.googleapis.com-nodejs-quickstart.json
const SCOPES = [
 
'https://www.googleapis.com/auth/presentations', // needed to create slides
 
'https://www.googleapis.com/auth/drive', // read and write files
 
'https://www.googleapis.com/auth/bigquery.readonly' // needed for bigquery
];

/**
 * Loads client secrets from a local file.
 * @return {Promise} A promise to return the secrets.
 */

module.exports.getClientSecrets = () => {
 
return new Promise((resolve, reject) => {
    fs
.readFile('client_secret.json', (err, content) => {
     
if (err) return reject('Error loading client secret file: ' + err);
      console
.log('loaded secrets...');
      resolve
(JSON.parse(content));
   
});
 
});
}

/**
 * Create an OAuth2 client promise with the given credentials.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback for the authorized client.
 * @return {Promise} A promise to return the OAuth client.
 */

module.exports.authorize = (credentials) => {
 
return new Promise((resolve, reject) => {
    console
.log('authorizing...');
   
const clientSecret = credentials.installed.client_secret;
   
const clientId = credentials.installed.client_id;
   
const redirectUrl = credentials.installed.redirect_uris[0];
   
const auth = new googleAuth();
   
const oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);

   
// Check if we have previously stored a token.
    fs
.readFile(TOKEN_PATH, (err, token) => {
     
if (err) {
        getNewToken
(oauth2Client).then(() => {
          resolve
(oauth2Client);
       
});
     
} else {
        oauth2Client
.credentials = JSON.parse(token);
        resolve
(oauth2Client);
     
}
   
});
 
});
}

/**
 * Get and store new token after prompting for user authorization, and then
 * fulfills the promise. Modifies the `oauth2Client` object.
 * @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
 * @return {Promise} A promise to modify the oauth2Client credentials.
 */

function getNewToken(oauth2Client) {
  console
.log('getting new auth token...');
  openurl
.open(oauth2Client.generateAuthUrl({
    access_type
: 'offline',
    scope
: SCOPES
 
}));

  console
.log(''); // \n
 
return new Promise((resolve, reject) => {
   
const rl = readline.createInterface({
      input
: process.stdin,
      output
: process.stdout
   
});
    rl
.question('Enter the code from that page here: ', (code) => {
      rl
.close();
      oauth2Client
.getToken(code, (err, token) => {
       
if (err) return reject(err);
        oauth2Client
.credentials = token;
        let storeTokenErr
= storeToken(token);
       
if (storeTokenErr) return reject(storeTokenErr);
        resolve
();
     
});
   
});
 
});
}

/**
 * Store token to disk be used in later program executions.
 * @param {Object} token The token to store to disk.
 * @return {Error?} Returns an error or undefined if there is no error.
 */

function storeToken(token) {
 
try {
    fs
.mkdirSync(TOKEN_DIR);
    fs
.writeFileSync(TOKEN_PATH, JSON.stringify(token));
 
} catch (err) {
   
if (err.code != 'EEXIST') return err;
 
}
  console
.log('Token stored to ' + TOKEN_PATH);
}

6. Настройка BigQuery

Изучите BigQuery (необязательно)

BigQuery позволяет нам запрашивать огромные наборы данных за считанные секунды. Давайте воспользуемся веб-интерфейсом, прежде чем делать программный запрос. Если вы никогда раньше не настраивали BigQuery, выполните действия, описанные в этом кратком руководстве .

Откройте Cloud Console , чтобы просмотреть данные GitHub, доступные в BigQuery, и выполнить собственные запросы. Давайте узнаем самые популярные лицензии на программное обеспечение на GitHub, написав этот запрос и нажав кнопку «Выполнить» .

bigquery.sql

WITH AllLicenses AS (
  SELECT
* FROM `bigquery-public-data.github_repos.licenses`
)
SELECT
  license
,
  COUNT
(*) AS count,
  ROUND
((COUNT(*) / (SELECT COUNT(*) FROM AllLicenses)) * 100, 2) AS percent
FROM
`bigquery-public-data.github_repos.licenses`
GROUP BY license
ORDER BY count DESC
LIMIT
10

Мы только что проанализировали миллионы публичных репозиториев на GitHub и выявили самые популярные лицензии. Прохладный! Теперь давайте настроим выполнение того же запроса, но на этот раз программно.

Настройка BigQuery

Замените код в файле license.js . Функция bigquery.query вернет обещание .

лицензия **.js**

const google = require('googleapis');
const read = require('read-file');
const BigQuery = require('@google-cloud/bigquery');
const bigquery = BigQuery({
  credentials
: require('./service_account_secret.json')
});

// See codelab for other queries.
const query = `
WITH AllLicenses AS (
  SELECT * FROM \`bigquery-public-data.github_repos.licenses\`
)
SELECT
  license,
  COUNT(*) AS count,
  ROUND((COUNT(*) / (SELECT COUNT(*) FROM AllLicenses)) * 100, 2) AS percent
FROM \`bigquery-public-data.github_repos.licenses\`
GROUP BY license
ORDER BY count DESC
LIMIT 10
`
;

/**
 * Get the license data from BigQuery and our license data.
 * @return {Promise} A promise to return an object of licenses keyed by name.
 */

module.exports.getLicenseData = (auth) => {
  console
.log('querying BigQuery...');
 
return bigquery.query({
    query
,
    useLegacySql
: false,
    useQueryCache
: true,
 
}).then(bqData => Promise.all(bqData[0].map(getLicenseText)))
   
.then(licenseData => new Promise((resolve, reject) => {
      resolve
([auth, licenseData]);
   
}))
   
.catch((err) => console.error('BigQuery error:', err));
}

/**
 * Gets a promise to get the license text about a license
 * @param {object} licenseDatum An object with the license's
 *   `license`, `count`, and `percent`
 * @return {Promise} A promise to return license data with license text.
 */

function getLicenseText(licenseDatum) {
 
const licenseName = licenseDatum.license;
 
return new Promise((resolve, reject) => {
    read
(`licenses/${licenseName}.txt`, 'utf8', (err, buffer) => {
     
if (err) return reject(err);
      resolve
({
        licenseName
,
        count
: licenseDatum.count,
        percent
: licenseDatum.percent,
        license
: buffer.substring(0, 1200) // first 1200 characters
     
});
   
});
 
});
}

Попробуйте console.log некоторые данные внутри обратного вызова нашего промиса, чтобы понять структуру наших объектов и увидеть работу кода в действии.

7. Создать слайды

Теперь самое интересное! Давайте создадим слайды, вызвав методы create и batchUpdate API Slides. Наш файл следует заменить следующим:

слайды.js

const google = require('googleapis');
const slides = google.slides('v1');
const drive = google.drive('v3');
const openurl = require('openurl');
const commaNumber = require('comma-number');

const SLIDE_TITLE_TEXT = 'Open Source Licenses Analysis';

/**
 * Get a single slide json request
 * @param {object} licenseData data about the license
 * @param {object} index the slide index
 * @return {object} The json for the Slides API
 * @example licenseData: {
 *            "licenseName": "mit",
 *            "percent": "12.5",
 *            "count": "1667029"
 *            license:"<body>"
 *          }
 * @example index: 3
 */

function createSlideJSON(licenseData, index) {
 
// Then update the slides.
 
const ID_TITLE_SLIDE = 'id_title_slide';
 
const ID_TITLE_SLIDE_TITLE = 'id_title_slide_title';
 
const ID_TITLE_SLIDE_BODY = 'id_title_slide_body';

 
return [{
   
// Creates a "TITLE_AND_BODY" slide with objectId references
    createSlide
: {
      objectId
: `${ID_TITLE_SLIDE}_${index}`,
      slideLayoutReference
: {
        predefinedLayout
: 'TITLE_AND_BODY'
     
},
      placeholderIdMappings
: [{
        layoutPlaceholder
: {
          type
: 'TITLE'
       
},
        objectId
: `${ID_TITLE_SLIDE_TITLE}_${index}`
     
}, {
        layoutPlaceholder
: {
          type
: 'BODY'
       
},
        objectId
: `${ID_TITLE_SLIDE_BODY}_${index}`
     
}]
   
}
 
}, {
   
// Inserts the license name, percent, and count in the title
    insertText
: {
      objectId
: `${ID_TITLE_SLIDE_TITLE}_${index}`,
      text
: `#${index + 1} ${licenseData.licenseName}  — ~${licenseData.percent}% (${commaNumber(licenseData.count)} repos)`
   
}
 
}, {
   
// Inserts the license in the text body paragraph
    insertText
: {
      objectId
: `${ID_TITLE_SLIDE_BODY}_${index}`,
      text
: licenseData.license
   
}
 
}, {
   
// Formats the slide paragraph's font
    updateParagraphStyle
: {
      objectId
: `${ID_TITLE_SLIDE_BODY}_${index}`,
      fields
: '*',
      style
: {
        lineSpacing
: 10,
        spaceAbove
: {magnitude: 0, unit: 'PT'},
        spaceBelow
: {magnitude: 0, unit: 'PT'},
     
}
   
}
 
}, {
   
// Formats the slide text style
    updateTextStyle
: {
      objectId
: `${ID_TITLE_SLIDE_BODY}_${index}`,
      style
: {
        bold
: true,
        italic
: true,
        fontSize
: {
          magnitude
: 10,
          unit
: 'PT'
       
}
     
},
      fields
: '*',
   
}
 
}];
}

/**
 * Creates slides for our presentation.
 * @param {authAndGHData} An array with our Auth object and the GitHub data.
 * @return {Promise} A promise to return a new presentation.
 * @see https://developers.google.com/apis-explorer/#p/slides/v1/
 */

module.exports.createSlides = (authAndGHData) => new Promise((resolve, reject) => {
  console
.log('creating slides...');
 
const [auth, ghData] = authAndGHData;

 
// First copy the template slide from drive.
  drive
.files.copy({
    auth
: auth,
    fileId
: '1toV2zL0PrXJOfFJU-NYDKbPx9W0C4I-I8iT85TS0fik',
    fields
: 'id,name,webViewLink',
    resource
: {
      name
: SLIDE_TITLE_TEXT
   
}
 
}, (err, presentation) => {
   
if (err) return reject(err);

   
const allSlides = ghData.map((data, index) => createSlideJSON(data, index));
    slideRequests
= [].concat.apply([], allSlides); // flatten the slide requests
    slideRequests
.push({
      replaceAllText
: {
        replaceText
: SLIDE_TITLE_TEXT,
        containsText
: { text: '{{TITLE}}' }
     
}
   
})

   
// Execute the requests
    slides
.presentations.batchUpdate({
      auth
: auth,
      presentationId
: presentation.id,
      resource
: {
        requests
: slideRequests
     
}
   
}, (err, res) => {
     
if (err) {
        reject
(err);
     
} else {
        resolve
(presentation);
     
}
   
});
 
});
});

8. Открыть слайды

Наконец, давайте откроем презентацию в браузере. Обновите следующий метод в slides.js .

слайды.js

/**
 * Opens a presentation in a browser.
 * @param {String} presentation The presentation object.
 */

module.exports.openSlidesInBrowser = (presentation) => {
  console
.log('Presentation URL:', presentation.webViewLink);
  openurl
.open(presentation.webViewLink);
}

Запустите проект в последний раз, чтобы увидеть окончательный результат.

9. Поздравляем!

Вы успешно создали Google Slides на основе данных, проанализированных с помощью BigQuery. Ваш скрипт создает презентацию с использованием API Google Slides и BigQuery для анализа наиболее распространенных лицензий на программное обеспечение.

Возможные улучшения

Вот несколько дополнительных идей для еще более привлекательной интеграции:

  • Добавляйте изображения на каждый слайд
  • Поделитесь своими слайдами по электронной почте с помощью API Gmail.
  • Настройте слайд шаблона в качестве аргумента командной строки.

Узнать больше