API에 연결하기: 의견 감정 분석

코딩 수준: 중급
기간: 20분
프로젝트 유형: 맞춤 메뉴를 사용한 자동화

목표

  • 솔루션의 기능을 이해합니다.
  • 솔루션 내에서 Apps Script 서비스가 하는 작업을 이해합니다.
  • 환경을 설정합니다.
  • 스크립트를 설정합니다.
  • 스크립트를 실행합니다.

이 솔루션 정보

서술형 의견과 같은 텍스트 데이터를 대규모로 분석할 수 있습니다. 이 솔루션은 Google 스프레드시트 내에서 항목 및 감정 분석을 수행하기 위해 UrlFetch 서비스를 사용하여 Google Cloud Natural Language API에 연결합니다.

감정 분석 작동 방식 다이어그램

사용 방법

스크립트는 스프레드시트에서 텍스트를 수집하고 Google Cloud Natural Language API에 연결하여 문자열에 있는 항목과 감정을 분석합니다. 피벗 테이블에는 텍스트 데이터의 모든 행에서 언급된 각 항목의 평균 감정 점수가 요약되어 있습니다.

Apps Script 서비스

이 솔루션은 다음 서비스를 사용합니다.

  • 스프레드시트 서비스 - 텍스트 데이터를 Google Cloud Natural Language API로 전송하고 감정이 분석되면 각 행을 '완료'로 표시합니다.
  • UrlFetch 서비스–Google Cloud Natural Language API에 연결하여 텍스트에 대한 항목 및 감정 분석을 수행합니다.

기본 요건

이 샘플을 사용하려면 다음과 같은 기본 요건이 필요합니다.

  • Google 계정 (Google Workspace 계정은 관리자 승인이 필요할 수 있음)
  • 인터넷에 액세스할 수 있는 웹브라우저

  • 결제 계정이 연결된 Google Cloud 프로젝트 프로젝트의 결제 사용 설정을 참조하세요.

환경 설정하기

Google Cloud 콘솔에서 Cloud 프로젝트 열기

이 샘플에 사용할 Cloud 프로젝트가 아직 열려 있지 않으면 엽니다.

  1. Google Cloud 콘솔에서 프로젝트 선택 페이지로 이동합니다.

    Cloud 프로젝트 선택

  2. 사용할 Google Cloud 프로젝트를 선택합니다. 또는 프로젝트 만들기를 클릭하고 화면에 표시된 안내를 따릅니다. Google Cloud 프로젝트를 만드는 경우 프로젝트에 결제를 사용 설정해야 할 수도 있습니다.

Google Cloud Natural Language API 사용 설정

이 솔루션은 Google Cloud Natural Language API에 연결됩니다. Google API를 사용하려면 먼저 Google Cloud 프로젝트에서 사용 설정해야 합니다. 단일 Google Cloud 프로젝트에서 하나 이상의 API를 사용 설정할 수 있습니다.

  • Cloud 프로젝트에서 Google Cloud Natural Language API를 사용 설정합니다.

    API 사용 설정

이 솔루션에는 동의 화면이 구성된 Cloud 프로젝트가 필요합니다. OAuth 동의 화면을 구성하면 Google에서 사용자에게 표시하는 내용을 정의하고 나중에 게시할 수 있도록 앱을 등록합니다.

  1. Google Cloud 콘솔에서 메뉴 > API 및 서비스 > OAuth 동의 화면으로 이동합니다.

    OAuth 동의 화면으로 이동

  2. 사용자 유형에서 내부를 선택한 다음 만들기를 클릭합니다.
  3. 앱 등록 양식을 작성한 다음 저장하고 계속하기를 클릭합니다.
  4. 지금은 범위 추가를 건너뛰고 저장 후 계속을 클릭해도 됩니다. 앞으로 Google Workspace 조직 외부에서 사용할 앱을 만들 때는 사용자 유형외부로 변경한 후 앱에 필요한 승인 범위를 추가해야 합니다.

  5. 앱 등록 요약을 검토합니다. 변경하려면 수정을 클릭합니다. 앱 등록이 확인되면 대시보드로 돌아가기를 클릭합니다.

Google Cloud Natural Language API의 API 키 가져오기

  1. Google Cloud 콘솔로 이동합니다. 결제가 사용 설정된 프로젝트가 열려 있는지 확인하세요.
  2. Google Cloud 콘솔에서 메뉴 > API 및 서비스 > 사용자 인증 정보로 이동합니다.

    사용자 인증 정보로 이동

  3. 사용자 인증 정보 만들기 > API 키를 클릭합니다.

  4. 이후 단계에서 사용할 수 있도록 API 키를 기록해 둡니다.

스크립트 설정

Apps Script 프로젝트 만들기

  1. 아래 버튼을 클릭하여 의견에 대한 감정 분석 샘플 스프레드시트의 사본을 만듭니다. 이 솔루션의 Apps Script 프로젝트는 스프레드시트에 연결되어 있습니다.
    사본 만들기
  2. 확장 프로그램 > Apps Script를 클릭합니다.
  3. 스크립트 파일에서 API 키로 다음 변수를 업데이트합니다.
    const myApiKey = 'YOUR_API_KEY'; // Replace with your API key.
  4. 저장 저장 아이콘를 클릭합니다.

텍스트 데이터 추가

  1. 스프레드시트로 돌아갑니다.
  2. idcomments 열에 텍스트 데이터를 추가합니다. Kaggle의 휴가 부동산 리뷰 샘플을 사용하거나 자체 데이터를 사용할 수 있습니다. 필요한 경우 열을 추가할 수 있지만 성공적으로 실행하려면 스크립트의 idcomments 열에 데이터가 있어야 합니다.

스크립트 실행

  1. 스프레드시트 상단에서 감정 도구 > 항목 및 감정 표시를 클릭합니다. 이 맞춤 메뉴를 표시하려면 페이지를 새로고침해야 할 수 있습니다.
  2. 메시지가 표시되면 스크립트를 승인합니다. OAuth 동의 화면에 이 앱이 확인되지 않았습니다라는 경고가 표시되면 고급 > {프로젝트 이름}으로 이동(안전하지 않음)을 선택하여 계속 진행합니다.

  3. 감정 도구 > 항목 및 감정 표시를 다시 클릭합니다.

  4. 스크립트가 완료되면 피벗 테이블 시트로 전환하여 결과를 확인합니다.

코드 검토

이 솔루션의 Apps Script 코드를 검토하려면 아래의 소스 코드 보기를 클릭하세요.

소스 코드 보기

Code.gs

solutions/automations/feedback-sentiment-analysis/code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/feedback-sentiment-analysis

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Sets API key for accessing Cloud Natural Language API.
const myApiKey = 'YOUR_API_KEY'; // Replace with your API key.

// Matches column names in Review Data sheet to variables.
let COLUMN_NAME = {
  COMMENTS: 'comments',
  ENTITY: 'entity_sentiment',
  ID: 'id'
};

/**
 * Creates a Demo menu in Google Spreadsheets.
 */
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Sentiment Tools')
    .addItem('Mark entities and sentiment', 'markEntitySentiment')
    .addToUi();
};

/**
* Analyzes entities and sentiment for each comment in  
* Review Data sheet and copies results into the 
* Entity Sentiment Data sheet.
*/
function markEntitySentiment() {
  // Sets variables for "Review Data" sheet
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let dataSheet = ss.getSheetByName('Review Data');
  let rows = dataSheet.getDataRange();
  let numRows = rows.getNumRows();
  let values = rows.getValues();
  let headerRow = values[0];

  // Checks to see if "Entity Sentiment Data" sheet is present, and
  // if not, creates a new sheet and sets the header row.
  let entitySheet = ss.getSheetByName('Entity Sentiment Data');
  if (entitySheet == null) {
   ss.insertSheet('Entity Sentiment Data');
   let entitySheet = ss.getSheetByName('Entity Sentiment Data');
   let esHeaderRange = entitySheet.getRange(1,1,1,6);
   let esHeader = [['Review ID','Entity','Salience','Sentiment Score',
                    'Sentiment Magnitude','Number of mentions']];
   esHeaderRange.setValues(esHeader);
  };

  // Finds the column index for comments, language_detected, 
  // and comments_english columns.
  let textColumnIdx = headerRow.indexOf(COLUMN_NAME.COMMENTS);
  let entityColumnIdx = headerRow.indexOf(COLUMN_NAME.ENTITY);
  let idColumnIdx = headerRow.indexOf(COLUMN_NAME.ID);
  if (entityColumnIdx == -1) {
    Browser.msgBox("Error: Could not find the column named " + COLUMN_NAME.ENTITY + 
                   ". Please create an empty column with header \"entity_sentiment\" on the Review Data tab.");
    return; // bail
  };

  ss.toast("Analyzing entities and sentiment...");
  for (let i = 0; i < numRows; ++i) {
    let value = values[i];
    let commentEnCellVal = value[textColumnIdx];
    let entityCellVal = value[entityColumnIdx];
    let reviewId = value[idColumnIdx];

    // Calls retrieveEntitySentiment function for each row that has a comment 
    // and also an empty entity_sentiment cell value.
    if(commentEnCellVal && !entityCellVal) {
        let nlData = retrieveEntitySentiment(commentEnCellVal);
        // Pastes each entity and sentiment score into Entity Sentiment Data sheet.
        let newValues = []
        for (let entity in nlData.entities) {
          entity = nlData.entities [entity];
          let row = [reviewId, entity.name, entity.salience, entity.sentiment.score, 
                     entity.sentiment.magnitude, entity.mentions.length
                    ];
          newValues.push(row);
        }
      if(newValues.length) {
        entitySheet.getRange(entitySheet.getLastRow() + 1, 1, newValues.length, newValues[0].length).setValues(newValues);
      }
        // Pastes "complete" into entity_sentiment column to denote completion of NL API call.
        dataSheet.getRange(i+1, entityColumnIdx+1).setValue("complete");
     }
   }
};

/**
 * Calls the Cloud Natural Language API with a string of text to analyze
 * entities and sentiment present in the string.
 * @param {String} the string for entity sentiment analysis
 * @return {Object} the entities and related sentiment present in the string
 */
function retrieveEntitySentiment (line) {
  let apiKey = myApiKey;
  let apiEndpoint = 'https://language.googleapis.com/v1/documents:analyzeEntitySentiment?key=' + apiKey;
  // Creates a JSON request, with text string, language, type and encoding
  let nlData = {
    document: {
      language: 'en-us',
      type: 'PLAIN_TEXT',
      content: line
    },
    encodingType: 'UTF8'
  };
  // Packages all of the options and the data together for the API call.
  let nlOptions = {
    method : 'post',
    contentType: 'application/json',  
    payload : JSON.stringify(nlData)
  };
  // Makes the API call.
  let response = UrlFetchApp.fetch(apiEndpoint, nlOptions);
  return JSON.parse(response);
};

기여자

이 샘플은 Google Developer Expert의 도움을 받아 Google에서 관리합니다.

다음 단계