Google পত্রকগুলিতে CSV ডেটা আমদানি স্বয়ংক্রিয় করতে ক্লাউড ফাংশন৷

১. ভূমিকা

এই কোডল্যাবের উদ্দেশ্য হলো, ক্লাউড স্টোরেজে একটি CSV ফাইল আপলোড হলে তার প্রতিক্রিয়া জানাতে, সেটির বিষয়বস্তু পড়তে এবং শীটস এপিআই (Sheets API) ব্যবহার করে একটি গুগল শীট আপডেট করার জন্য কীভাবে একটি ক্লাউড ফাংশন লিখতে হয়, তা আপনাকে বোঝানো।

e9c78061022a6760.png

এটিকে 'CSV হিসেবে ইম্পোর্ট' করার একটি ম্যানুয়াল ধাপের স্বয়ংক্রিয়করণ হিসেবে দেখা যেতে পারে। এর ফলে, ডেটা (যা হয়তো অন্য কোনো দল তৈরি করেছে) পাওয়া মাত্রই আপনি একটি স্প্রেডশিটে তা বিশ্লেষণ করতে পারবেন।

বাস্তবায়নটি দেখতে এইরকম:

52df703605ae4bd3.png

২. সেটআপ এবং প্রয়োজনীয়তা

স্ব-গতিতে পরিবেশ সেটআপ

  1. ক্লাউড কনসোলে সাইন ইন করুন এবং একটি নতুন প্রজেক্ট তৈরি করুন অথবা বিদ্যমান কোনো প্রজেক্ট পুনরায় ব্যবহার করুন। (যদি আপনার আগে থেকে Gmail বা G Suite অ্যাকাউন্ট না থাকে, তবে আপনাকে অবশ্যই একটি তৈরি করতে হবে।)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLpGtQd5Q55

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5 OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

প্রজেক্ট আইডিটি মনে রাখবেন, যা সমস্ত গুগল ক্লাউড প্রজেক্ট জুড়ে একটি অনন্য নাম (উপরের নামটি ইতিমধ্যে ব্যবহৃত হয়েছে এবং আপনার জন্য কাজ করবে না, দুঃখিত!)। এই কোডল্যাবে এটিকে পরবর্তীতে PROJECT_ID হিসাবে উল্লেখ করা হবে।

  1. এরপরে, গুগল ক্লাউড রিসোর্স ব্যবহার করার জন্য আপনাকে ক্লাউড কনসোলে বিলিং চালু করতে হবে।

এই কোডল্যাবটি চালাতে খুব বেশি খরচ হওয়ার কথা নয়, এমনকি আদৌ কোনো খরচ নাও হতে পারে। "পরিষ্কার-পরিচ্ছন্নতা" (Cleaning up) বিভাগে দেওয়া নির্দেশাবলী অবশ্যই অনুসরণ করবেন, যেখানে রিসোর্স বন্ধ করার পরামর্শ দেওয়া হয়েছে, যাতে এই টিউটোরিয়ালের বাইরে আপনার কোনো বিল না আসে। গুগল ক্লাউডের নতুন ব্যবহারকারীরা ৩০০ মার্কিন ডলারের ফ্রি ট্রায়াল প্রোগ্রামের জন্য যোগ্য।

৩. একটি গুগল শিট তৈরি ও কনফিগার করুন এবং এপিআই (API) সক্রিয় করুন।

প্রথমে, চলুন একটি নতুন শীটস ডকুমেন্ট তৈরি করি (এই শীটটি যেকোনো ব্যবহারকারীর হতে পারে)। তৈরি হয়ে গেলে, এর আইডেন্টিফায়ারটি মনে রাখবেন; আমরা যে ফাংশনটি লিখব, তার জন্য এটি একটি এনভায়রনমেন্ট ভেরিয়েবল হিসেবে ব্যবহৃত হবে।

dd77d5fc1364ad3e.png

GCP কনসোল থেকে, আপনার নতুন তৈরি করা প্রজেক্টে Google Sheets API সক্রিয় করতে 'APIs and Services' এবং তারপর 'API Library' বিভাগে যান:

c64e2e98b8b55f16.png

"IAM & admin" বিভাগে, "Service accounts"-এ যান এবং App Engine-এর ডিফল্ট সার্ভিস অ্যাকাউন্টের ইমেলটি নোট করুন। এটি your-project-id@appspot.gserviceaccount.com এই ধরনের হওয়া উচিত। অবশ্যই, আপনি এই কাজের জন্য আপনার নিজস্ব একটি সার্ভিস অ্যাকাউন্টও তৈরি করতে পারেন।

6e279d7e07d4febf.png

অবশেষে, 'শেয়ার' বোতামটি ব্যবহার করে এই সার্ভিস অ্যাকাউন্টটিকে আপনার স্প্রেডশীট সম্পাদনা করার অনুমতি দিন:

c334062465ddf928.png

এই সেটআপের মাধ্যমে আমরা এখন আমাদের ক্লাউড ফাংশনটি লিখতে এবং এই সার্ভিস অ্যাকাউন্টটি ব্যবহার করার জন্য কনফিগার করতে পারি। এটি আমাদের এইমাত্র তৈরি করা স্প্রেডশিট ডকুমেন্টটিতে লিখতে সক্ষম হবে।

৪. একটি স্টোরেজ বাকেট তৈরি করুন

চলুন সেই বাকেটটি তৈরি করি, যেটি আমাদের ক্লাউড ফাংশন নতুন CSV ফাইলগুলোর জন্য মনিটর করবে।

কনসোলে, বাম দিকের মেনু ব্যবহার করে "স্টোরেজ"-এ যান... :

2ddcb54423979d25.png

... এবং csv2sheet-POSTFIX (POSTFIX-এর জায়গায় একটি অনন্য কিছু বসান) নামে একটি নতুন বাকেট তৈরি করুন, যার অন্যান্য সমস্ত সেটিংস তাদের ডিফল্ট মানে সেট করা থাকবে:

dd637080ade62e81.png

৫. ক্লাউড ফাংশন তৈরি করুন

আমরা এখন csv2sheet নামে একটি ক্লাউড ফাংশন তৈরি করতে পারি, যা একটি নির্দিষ্ট ক্লাউড স্টোরেজ বাকেটে ফাইল আপলোড হলে চালু হবে। কোডটি সরাসরি ক্লাউড কনসোলের ইনলাইন এডিটর ব্যবহার করে নোড.জেএস ৮ (Node.js 8) ভাষায় অ্যাসিঙ্ক (async) ফাংশনসহ লেখা হবে।

6ee1a5ce63174ae8.png

ট্রিগারটি 'ক্লাউড স্টোরেজ'-এ সেট করতে এবং বাকেটের নামটি আগের ধাপে তৈরি করা নামটি অনুযায়ী পরিবর্তন করতে ভুলবেন না।

এছাড়াও, আমরা যে ফাংশনটি csv2sheet এ লিখতে চলেছি তার এন্ট্রিপয়েন্টটি আপডেট করুন:

446e7c7c992c2d8a.png

এখন ফাংশন বডিটি পরিবর্তন করে এটি করুন:

  1. ক্লাউড স্টোরেজ এবং শীটস এপিআই ব্যবহার করুন
  2. csv2sheet ফাংশনটিকে async হিসেবে চিহ্নিত করুন।
  3. ক্লাউড স্টোরেজ ইভেন্ট মেটাডেটা থেকে fileName সংগ্রহ করুন এবং আমরা যে নতুন শীটটি তৈরি করব তার জন্য একটি নাম নির্ধারণ করুন:
const {google} = require("googleapis");
const {Storage} = require("@google-cloud/storage")

exports.csv2sheet = async (data, context) => {
  var fileName = data.name;
  // basic check that this is a *.csv file, etc...
  if (!fileName.endsWith(".csv")) {
    console.log("Not a .csv file, ignoring.");
    return;
  }
  // define name of new sheet  
  const sheetName = fileName.slice(0, -4);

  // TODO!
};

এখানে async ব্যবহারের জন্য await ব্যবহার করা প্রয়োজন, যা আমরা একটু পরেই দেখতে পাব।

এই ফাংশনটি তৈরি করার সময় কয়েকটি গুরুত্বপূর্ণ বিকল্প হলো (স্ক্রিনের নীচে থাকা 'More' লিঙ্কে ক্লিক করুন):

  • উপরে আলোচিত পরিষেবা অ্যাকাউন্টটি নির্বাচন করতে ড্রপডাউনটি ব্যবহার করুন।
  • SPREADSHEET_ID নামে একটি এনভায়রনমেন্ট ভেরিয়েবল নির্ধারণ করুন যা আপনার পূর্বে তৈরি করা শীট ডকুমেন্টের সাথে মিলবে:

fd22d1873bcb8c66.png

চূড়ান্ত সেটআপ ধাপ হিসেবে, এখানে package.json ফাইলের বিষয়বস্তু দেওয়া হলো, যেখানে আমরা দুটি ডিপেন্ডেন্সি হিসেবে ক্লাউড স্টোরেজ এবং গুগল শীট এপিআই ব্যবহার করব (কনসোলের ইনলাইন এডিটর PACKAGE.JSON ট্যাবটি ব্যবহার করুন):

{
    "name": "csv2sheet",
    "version": "0.0.42",
    "dependencies": {
        "googleapis": "^51.0.0",
        "@google-cloud/storage": "^5.0.1"
    }
}

বর্ণনা অনুযায়ী সবকিছু কনফিগার করার পর, "Create" বাটনে ক্লিক করুন! কিছুক্ষণের মধ্যেই আপনার ফাংশনটি তৈরি এবং ডেপ্লয় হয়ে যাবে।

৬. অথেন্টিকেশন এবং শীটস এপিআই সেটআপ করুন

ইনলাইন এডিটর ব্যবহার করে আমাদের ক্লাউড ফাংশনে আরও কোড লেখার আগে, সঠিক স্টোরেজ এবং শীট স্কোপ সহ একটি গুগল ক্লায়েন্ট এপিআই তৈরি করার জন্য আমাদের ব্লক করতে হবে (মনে রাখবেন, এটি একটি async ফাংশনের অংশ)।

কনসোলের ফাংশন এডিটরে, "EDIT"-এ ক্লিক করুন এবং আপনার csv2sheet ফাংশনের বডিতে নিম্নলিখিত কোডটি যোগ করুন:

// block on auth + getting the sheets API object
const auth = await google.auth.getClient({
  scopes: [
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/devstorage.read_only"
  ]
});

সেখান থেকে আমরা একটি শীটস এপিআই ক্লায়েন্ট তৈরি করতে পারি:

const sheetsAPI = google.sheets({version: 'v4', auth});

৭. শীটস এপিআই ব্যবহার করে একটি খালি শীট তৈরি করুন।

একটি শীটস এপিআই ক্লায়েন্টের সাহায্যে আমরা আমাদের ডকুমেন্টে একটি সাধারণ নতুন শীট তৈরি করতে পারি, কিন্তু আরও অগ্রসর হওয়ার আগে, পরিভাষা সম্পর্কে এখানে একটি সংক্ষিপ্ত আলোচনা করা হলো:

  • একটি স্প্রেডশীট হলো প্রকৃত নথি এবং এটিকে এর শনাক্তকারী (যা উপরে আলোচনা করা হয়েছে এবং নথির URL-এ দৃশ্যমান) দ্বারা উল্লেখ করা হয়।
  • একটি শীট হলো ডকুমেন্টের ট্যাবগুলোর মধ্যে একটি এবং এটিকে এর নাম (ট্যাবের নাম) অথবা শীট তৈরির সময় উৎপন্ন হওয়া একটি শনাক্তকারী দ্বারা উল্লেখ করা যেতে পারে।

এই বিষয়টি মাথায় রেখে, এখানে শীটস এপিআই ক্লায়েন্ট ব্যবহার করে একটি ফাংশন দেওয়া হলো যা ২ নং অবস্থানে (সাধারণত ডিফল্ট "Sheet1"-এর পরে) ২৬টি কলাম ও ২০০০টি সারি সহ একটি খালি শীট তৈরি করবে, যার প্রথম সারিটি স্থির (ফ্রোজেন) থাকবে (ইনলাইন এডিটর ব্যবহার করে এটি আপনার ফাংশনে যোগ করুন):

function addEmptySheet(sheetsAPI, sheetName) {
  return new Promise((resolve, reject) => {
    const emptySheetParams = {
      spreadsheetId: process.env.SPREADSHEET_ID,
      resource: {
        requests: [
          {
            addSheet: {
              properties: {
                title: sheetName,
                index: 1,
                gridProperties: {
                  rowCount: 2000,
                  columnCount: 26,
                  frozenRowCount: 1
                }
              }
            }
          }
        ]
      }
    };
    sheetsAPI.spreadsheets.batchUpdate( emptySheetParams, function(err, response) {
        if (err) {
          reject("The Sheets API returned an error: " + err);
        } else {
          const sheetId = response.data.replies[0].addSheet.properties.sheetId;
          console.log("Created empty sheet: " + sheetId);
          resolve(sheetId);
        }
      }
    );
  });
}

লক্ষ্য করুন, কীভাবে আমরা স্প্রেডশীটের রেফারেন্সটি হার্ড-কোড করার পরিবর্তে পূর্বে তৈরি করা SPREADSHEET_ID এনভায়রনমেন্ট ভেরিয়েবলটির উপর নির্ভর করি।

এই নির্দিষ্ট শীটটিতে পরবর্তী অনুরোধগুলোর জন্য আমাদের sheetId মনে রাখতে হবে। এছাড়াও, শীটের নামটি অনন্য (unique) হতে হবে এবং যদি sheetName নামে আগে থেকেই কোনো শীট থাকে, তাহলে এটি তৈরি করার প্রক্রিয়া ব্যর্থ হবে।

শীটস এপিআই-এর batchUpdate ফাংশনটি ডকুমেন্টের সাথে ইন্টারঅ্যাক্ট করার একটি প্রচলিত উপায় এবং এটি এখানে বর্ণনা করা হয়েছে।

৮. স্টোরেজ CSV ফাইল থেকে ডেটা পড়ুন

এখন যেহেতু আমাদের ডেটা রাখার জন্য একটি জায়গা আছে, চলুন ইনলাইন এডিটরে আমাদের ক্লাউড ফাংশনটিকে আরও উন্নত করি এবং ক্লাউড স্টোরেজ এপিআই ব্যবহার করে এইমাত্র আপলোড করা ফাইলটি থেকে আসল ডেটা নিয়ে এসে একটি স্ট্রিং-এ সংরক্ষণ করি:

function readCSVContent(sheetsAPI, file, sheetName) {
  return new Promise((resolve, reject) => {
    const storage = new Storage();
    let fileContents = new Buffer('');
    storage.bucket(file.bucket).file(file.name).createReadStream()
    .on('error', function(err) {
      reject('The Storage API returned an error: ' + err);
    })
    .on('data', function(chunk) {
      fileContents = Buffer.concat([fileContents, chunk]);
    })  
    .on('end', function() {
      let content = fileContents.toString('utf8');
      console.log("CSV content read as string : " + content );
      resolve(content);
    });
  });
}

৯. নতুন তৈরি করা শীটটিতে তথ্য পূরণ করুন।

এখন সময় এসেছে একই শীট ক্লায়েন্ট এপিআই এবং এইমাত্র সংগ্রহ করা ডেটা ব্যবহার করে আমাদের তৈরি করা শীটটি পূরণ করার। এই সুযোগে আমরা শীটের কলামগুলোতে কিছু স্টাইলিংও যোগ করব (যেমন উপরের সারির ফন্ট সাইজ পরিবর্তন করে এবং এটিকে বোল্ড করে):

function populateAndStyle(sheetsAPI, theData, sheetId) {
  return new Promise((resolve, reject) => {
    // Using 'batchUpdate' allows for multiple 'requests' to be sent in a single batch.
    // Populate the sheet referenced by its ID with the data received (a CSV string)
    // Style: set first row font size to 11 and to Bold. Exercise left for the reader: resize columns
    const dataAndStyle = {
      spreadsheetId: process.env.SPREADSHEET_ID,
      resource: {
        requests: [
          {
            pasteData: {
              coordinate: {
                sheetId: sheetId,
                rowIndex: 0,
                columnIndex: 0
              },
              data: theData,
              delimiter: ","
            }
          },
          {
            repeatCell: {
              range: {
                sheetId: sheetId,
                startRowIndex: 0,
                endRowIndex: 1
              },
              cell: {
                userEnteredFormat: {
                  textFormat: {
                    fontSize: 11,
                    bold: true
                  }
                }
              },
              fields: "userEnteredFormat(textFormat)"
            }
          }       
        ]
      }
    };
        
    sheetsAPI.spreadsheets.batchUpdate(dataAndStyle, function(err, response) {
      if (err) {
        reject("The Sheets API returned an error: " + err);
      } else {
        console.log(sheetId + " sheet populated with " + theData.length + " rows and column style set.");
        resolve();
      }
    });    
  });
}

এই কোডটি আমাদের ক্লাউড ফাংশনে যোগ করতে হবে, যেটি এখন ৯৯% সম্পন্ন হয়েছে!

লক্ষ্য করুন, কীভাবে ডেটা এবং স্টাইলিং উভয়কেই একাধিক requests হিসেবে একটিমাত্র Sheets API batchUpdate কলের মধ্যে একত্রিত করা হয়। এর ফলে আপডেটটি আরও বেশি কার্যকর এবং অ্যাটমিক হয়।

আরও মনে রাখবেন যে, আমরা একটি এডিট রেঞ্জ নির্ধারণ করি যা আমাদের তৈরি করা শীটটির আকারের সাথে মেলে। এর মানে হলো, যে কন্টেন্টের কলাম সংখ্যা ২৬-এর বেশি (শীটটি তৈরি করার সময় ব্যবহৃত ` columnCount মান), তা এই নির্দিষ্ট কোডটির মাধ্যমে কাজ করবে না।

সবকিছু ঠিকঠাক থাকলে, এই পর্যায়ে আপনি যা করতে পারেন:

  1. আপডেট করা ফাংশনটি সংরক্ষণ করুন
  2. বালতিতে একটি CSV ফাইল ফেলুন
  3. আপনার স্প্রেডশীটে সংশ্লিষ্ট ডেটা ভেসে উঠতে দেখুন!

১০. সবকিছু একত্রিত করে প্রবাহ পরীক্ষা করা

আমরা এইমাত্র যে ফাংশনগুলো নিয়ে আলোচনা করেছি, সেগুলোকে মূল csv2sheet ফাংশনে ধারাবাহিক ব্লকিং কল হিসেবে করা যেতে পারে:

  const sheetId = await addEmptySheet(sheetsAPI, sheetName);
  const theData = await readCSVContent(sheetsAPI, data, sheetName);
  await populateAndStyle(sheetsAPI, theData, sheetId);

আপনার যদি সম্পূর্ণ ফাংশন সোর্স কোডের প্রয়োজন হয়, তবে তা এখানে পাওয়া যাবে (সম্ভবত একবারে সবকিছু পেয়ে যাওয়া আরও সহজ হবে)।

সবকিছু প্রস্তুত হয়ে গেলে, সঠিক বাকেটে একটি CSV ফাইল আপলোড করুন এবং দেখুন আপনার স্প্রেডশীটটি ফাইলটির বিষয়বস্তু দিয়ে একটি নতুন শীট দ্বারা আপডেট হয়ে যাচ্ছে। আপনার কাছে কোনো নমুনা CSV ফাইল না থাকলে, এখানে তার একটি নমুনা দেওয়া হলো।

1efae021942e64fa.png

কী হয় তা দেখতে বাকেটে কয়েকটি ফাইল আপলোড করে দেখুন!

১১. ব্যাস! এবার পরিকাঠামোটি ভেঙে ফেলার পালা।

মজা করছিলাম, ভেঙে ফেলার মতো কোনো পরিকাঠামোই নেই, এই সবকিছু সার্ভার ছাড়াই করা হয়েছে!

আপনি চাইলে, আপনার তৈরি করা ক্লাউড ফাংশন ও বাকেটটি, এমনকি পুরো প্রজেক্টটিও মুছে ফেলতে পারেন।

১২. এরপর কী?

উপযুক্ত এপিআই ব্যবহার করে একটি গুগল শিট আপডেট করার জন্য ক্লাউড ফাংশনে ক্লাউড স্টোরেজ বাকেটে আপলোড শোনার ধাপগুলো দেখানোর পর এই কোডল্যাবটি এখানেই শেষ হচ্ছে।

এখানে কিছু পরবর্তী পদক্ষেপ দেওয়া হলো:

এই কোডল্যাবটি নিয়ে কোনো সমস্যার সম্মুখীন হলে, নিচের বাম কোণে থাকা লিঙ্কটি ব্যবহার করে নির্দ্বিধায় সমস্যাটি জানান।

আপনার মতামতের জন্য ধন্যবাদ!