连接到 API:分析反馈情绪

编码水平:中级
时长:20 分钟
项目类型:使用自定义菜单实现自动化

目标

  • 了解解决方案的功能。
  • 了解 Apps 脚本服务在解决方案中的作用。
  • 设置环境。
  • 设置脚本。
  • 运行脚本。

关于此解决方案

您可以大规模分析各种文本数据,比如用户以自由作答形式提供的反馈。为了在 Google 表格中执行实体和情感分析,此解决方案使用 UrlFetch 服务连接到 Google Cloud Natural Language API

情感分析工作原理图

运作方式

该脚本从电子表格中收集文本,并连接到 Google Cloud Natural Language API 以分析字符串中存在的实体和情感。数据透视表会汇总所有文本数据行中提及的每个实体的平均情感得分。

Apps 脚本服务

此解决方案使用以下服务:

  • 电子表格服务 - 将文本数据发送到 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 控制台中,依次前往菜单 > Google Auth platform > 品牌推广

    前往“品牌推广”

  2. 如果您已配置 Google Auth platform,则可以在品牌受众群体数据访问中配置以下 OAuth 权限请求页面设置。如果您看到一条消息,指出Google Auth platform 尚未配置,请点击开始
    1. 应用信息下,在应用名称中输入应用的名称。
    2. 用户支持电子邮件中,选择一个支持电子邮件地址,以便用户在对自己的同意情况有疑问时与您联系。
    3. 点击下一步
    4. 受众群体下,选择内部
    5. 点击下一步
    6. 联系信息下,输入一个电子邮件地址,以便您接收有关项目变更的通知。
    7. 点击下一步
    8. 完成部分,查看 Google API 服务用户数据政策,如果您同意该政策,请选择我同意《Google API 服务:用户数据政策》
    9. 点击继续
    10. 点击创建
  3. 目前,您可以跳过添加范围的步骤。 未来,如果您创建的应用供 Google Workspace 组织以外的用户使用,则必须将用户类型更改为外部。然后,添加应用所需的授权范围。如需了解详情,请参阅完整的配置 OAuth 同意指南。

获取 Google Cloud Natural Language API 的 API 密钥

  1. 前往 Google Cloud 控制台。 确保您已打开已启用结算功能的项目。
  2. 在 Google Cloud 控制台中,依次前往菜单 > API 和服务 > 凭据

    转到“凭据”页面

  3. 依次点击创建凭据 > API 密钥

  4. 请记下您的 API 密钥,以便在后续步骤中使用。

设置脚本

创建 Apps 脚本项目

  1. 点击下方按钮,复制反馈情感分析示例电子表格。此解决方案的 Apps 脚本项目已附加到电子表格中。
    制作副本
  2. 依次点击扩展程序 > Google Apps 脚本
  3. 使用您的 API 密钥更新脚本文件中的以下变量:
    const myApiKey = 'YOUR_API_KEY'; // Replace with your API key.
  4. 点击“保存”图标 “保存”图标

添加文本数据

  1. 返回到电子表格。
  2. idcomments 列添加文本数据。您可以使用 Kaggle 中的度假住宿评价示例,也可以使用自己的数据。您可以根据需要添加更多列,但为了成功运行,脚本必须在 idcomments 列中包含数据。

运行脚本

  1. 在电子表格顶部,依次点击情感分析工具 > 标记实体和情感。您可能需要刷新页面才能看到此自定义菜单。
  2. 根据提示为脚本授权。 如果 OAuth 权限请求页面显示警告此应用未经过验证,请继续操作,依次选择高级 > 前往“{项目名称}”(不安全)

  3. 依次点击情感分析工具 > 再次点击标记实体和情感

  4. 脚本完成后,切换到数据透视表工作表以查看结果。

查看代码

如需查看此解决方案的 Apps 脚本代码,请点击下方的查看源代码

查看源代码

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 在 Google 开发者专家的帮助下维护。

后续步骤