1. ภาพรวม
ใน Codelab นี้ คุณจะได้เรียนรู้วิธีใช้ Google สไลด์เป็นเครื่องมืองานนำเสนอแบบกำหนดเองเพื่อวิเคราะห์ใบอนุญาตซอฟต์แวร์ที่นิยมใช้กันมากที่สุด คุณกำลังค้นหาโค้ดโอเพนซอร์สใน GitHub ทั้งหมดโดยใช้ BigQuery API และสร้างชุดสไลด์โดยใช้ Google สไลด์ API เพื่อนำเสนอผลลัพธ์ แอปพลิเคชันตัวอย่างสร้างขึ้นโดยใช้ Node.js แต่หลักการพื้นฐานเดียวกันนี้สามารถใช้ได้กับสถาปัตยกรรมทุกแบบ
สิ่งที่คุณจะได้เรียนรู้
- การสร้างงานนำเสนอโดยใช้ Slides API
- การใช้ BigQuery เพื่อรับข้อมูลเชิงลึกเกี่ยวกับชุดข้อมูลขนาดใหญ่
- การคัดลอกไฟล์โดยใช้ Google Drive API
สิ่งที่ต้องมี
- ติดตั้ง Node.js แล้ว
- การเข้าถึงอินเทอร์เน็ตและเว็บเบราว์เซอร์
- บัญชี Google
- โปรเจ็กต์ Google Cloud Platform
2. รับโค้ดตัวอย่าง
คุณจะดาวน์โหลดโค้ดตัวอย่างทั้งหมดลงในคอมพิวเตอร์ก็ได้...
...หรือโคลนที่เก็บ GitHub จากบรรทัดคำสั่ง
git clone https://github.com/googleworkspace/slides-api.git
ที่เก็บมีชุดไดเรกทอรีที่แสดงแต่ละขั้นตอนตลอดกระบวนการในกรณีที่คุณต้องอ้างอิงถึงเวอร์ชันที่ใช้งานได้
คุณจะทำงานกับสำเนาที่อยู่ในไดเรกทอรี start
แต่คุณสามารถอ้างอิงหรือคัดลอกไฟล์จากสำเนาอื่นๆ ได้ตามต้องการ
3. เรียกใช้แอปตัวอย่าง
ก่อนอื่น มาทำให้สคริปต์โหนดพร้อมทำงาน เมื่อดาวน์โหลดโค้ดแล้ว ให้ทำตามวิธีการด้านล่างเพื่อติดตั้งและเริ่มแอปพลิเคชัน Node.js
- เปิดเทอร์มินัลบรรทัดคำสั่งในคอมพิวเตอร์และไปที่ไดเรกทอรี
start
ของ Codelab - ป้อนคำสั่งต่อไปนี้เพื่อติดตั้งทรัพยากร Dependency ของ Node.js
npm install
- ป้อนคำสั่งต่อไปนี้เพื่อเรียกใช้สคริปต์
node .
- สังเกตคำทักทายที่แสดงขั้นตอนสำหรับโปรเจ็กต์นี้
-- Start generating slides. --
TODO: Get Client Secrets
TODO: Authorize
TODO: Get Data from BigQuery
TODO: Create Slides
TODO: Open Slides
-- Finished generating slides. --
คุณสามารถดูรายการสิ่งที่ต้องทำได้ใน slides.js
, license.js
และ auth.js
โปรดทราบว่าเราใช้ JavaScript Promises เพื่อเชื่อมโยงขั้นตอนที่จำเป็นในการดำเนินการแอปให้เสร็จสมบูรณ์ เนื่องจากแต่ละขั้นตอนจะขึ้นอยู่กับขั้นตอนก่อนหน้าที่ดำเนินการจนเสร็จสิ้น
หากคุณไม่คุ้นเคยกับสัญญา ไม่ต้องกังวล เราจะให้รหัสทั้งหมดที่คุณต้องใช้ กล่าวโดยสรุปคือ คำสัญญาจะช่วยให้เราสามารถจัดการกับการประมวลผลที่ไม่พร้อมกันในลักษณะที่โหลดพร้อมกันได้มากขึ้น
4. รับรหัสลับไคลเอ็นต์
ในการใช้สไลด์ API, BigQuery และ API ไดรฟ์ เราจะสร้างไคลเอ็นต์ OAuth และบัญชีบริการ
ตั้งค่า Google Developers Console
- ใช้วิซาร์ดนี้เพื่อสร้างหรือเลือกโปรเจ็กต์ใน Google Developers Console แล้วเปิด API โดยอัตโนมัติ คลิกต่อไป แล้วคลิกไปที่ข้อมูลเข้าสู่ระบบ
- ในหน้าเพิ่มข้อมูลเข้าสู่ระบบในโครงการ ให้คลิกปุ่มยกเลิก
- เลือกแท็บหน้าจอขอความยินยอม OAuth ที่ด้านบนของหน้า เลือกที่อยู่อีเมล ป้อนชื่อผลิตภัณฑ์
Slides API Codelab
แล้วคลิกปุ่มบันทึก
เปิดใช้ API ของ BigQuery, ไดรฟ์ และสไลด์
- เลือกแท็บแดชบอร์ด คลิกปุ่มเปิดใช้ API และเปิดใช้ API 3 รายการต่อไปนี้
- BigQuery API
- Google ไดรฟ์ API
- API ของ Google สไลด์
ดาวน์โหลดรหัสลับไคลเอ็นต์ OAuth (สำหรับสไลด์และไดรฟ์)
- เลือกแท็บข้อมูลเข้าสู่ระบบ แล้วคลิกปุ่มสร้างข้อมูลเข้าสู่ระบบ แล้วเลือกรหัสไคลเอ็นต์ OAuth
- เลือกประเภทแอปพลิเคชัน Other ป้อนชื่อ
Google Slides API Codelab
และคลิกปุ่ม สร้าง คลิก OK เพื่อปิดกล่องโต้ตอบที่ปรากฏขึ้น - คลิกปุ่ม file_download (ดาวน์โหลด JSON) ทางด้านขวาของรหัสไคลเอ็นต์
- เปลี่ยนชื่อไฟล์ลับเป็น
client_secret.json
และคัดลอกลงในไดเรกทอรี start/ และ finish/
ดาวน์โหลดข้อมูลลับของบัญชีบริการ (สำหรับ BigQuery)
- เลือกแท็บข้อมูลเข้าสู่ระบบ แล้วคลิกปุ่มสร้างข้อมูลเข้าสู่ระบบ แล้วเลือกคีย์บัญชีบริการ
- เลือกบัญชีบริการใหม่ในเมนูแบบเลื่อนลง เลือกชื่อ
Slides API Codelab Service
สำหรับบริการ จากนั้นคลิกบทบาท แล้วเลื่อนไปที่ BigQuery แล้วเลือกทั้งผู้ดูข้อมูล BigQuery และผู้ใช้งาน BigQuery - สำหรับประเภทคีย์ ให้เลือก JSON
- คลิกสร้าง ระบบจะดาวน์โหลดไฟล์คีย์ลงในคอมพิวเตอร์โดยอัตโนมัติ คลิกปิดเพื่อออกจากกล่องโต้ตอบที่ปรากฏ
- เปลี่ยนชื่อไฟล์ลับเป็น
service_account_secret.json
และคัดลอกลงในไดเรกทอรี start/ และ finish/
รับรหัสลับไคลเอ็นต์
ใน start/auth.js
มากรอกเมธอด getClientSecrets
กัน
auth.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
ในการสร้างสไลด์ ให้เพิ่มการตรวจสอบสิทธิ์ไปยัง Google APIs โดยการเพิ่มโค้ดต่อไปนี้ในไฟล์ auth.js ของเรา การตรวจสอบสิทธิ์นี้จะขอสิทธิ์เข้าถึงบัญชี Google เพื่ออ่านและเขียนไฟล์ใน Google ไดรฟ์ สร้างงานนำเสนอใน Google สไลด์ และดำเนินการค้นหาแบบอ่านอย่างเดียวจาก Google BigQuery (หมายเหตุ: เราไม่ได้เป็นผู้เปลี่ยน getClientSecrets
)
auth.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
จะแสดงผลคำสัญญา
license**.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
ข้อมูลบางส่วนภายใน Callback ของ Promise เพื่อให้เข้าใจโครงสร้างของออบเจ็กต์ของเรา และดูว่าโค้ดทำงานได้จริง
7. สร้างสไลด์
มาถึงส่วนที่สนุกแล้ว! ลองสร้างสไลด์โดยเรียกใช้เมธอด create
และ batchUpdate
ของ Slides 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
slides.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 สไลด์เรียบร้อยแล้วจากข้อมูลที่วิเคราะห์โดยใช้ BigQuery สคริปต์ของคุณจะสร้างงานนำเสนอโดยใช้ Google สไลด์ API และ BigQuery เพื่อรายงานการวิเคราะห์ใบอนุญาตซอฟต์แวร์ที่พบบ่อยที่สุด
สิ่งที่ปรับปรุงได้
ต่อไปนี้เป็นแนวคิดเพิ่มเติมในการสร้างการผสานรวมที่น่าสนใจยิ่งขึ้น
- เพิ่มรูปภาพในแต่ละสไลด์
- แชร์สไลด์ทางอีเมลโดยใช้ Gmail API
- ปรับแต่งสไลด์เทมเพลตเป็นอาร์กิวเมนต์บรรทัดคำสั่ง
ดูข้อมูลเพิ่มเติม
- อ่านเอกสารประกอบสำหรับนักพัฒนาซอฟต์แวร์ Google สไลด์ API
- โพสต์คำถามและหาคำตอบบน Stack Overflow ใต้แท็ก google-slides-api