连接到 API:分析反馈情绪

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

目标

  • 了解此解决方案的用途。
  • 了解 Apps 脚本服务在 解决方案。
  • 设置环境。
  • 设置脚本。
  • 运行脚本。

关于此解决方案

您可以大规模分析文本数据,例如开放式反馈。要执行 实体和情感分析,此解决方案使用 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 项目中启用这些 API。 您可以在单个 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. 查看您的应用注册摘要。如要进行更改,请点击修改。如果应用 点击 Back to Dashboard(返回信息中心)。

获取 Google Cloud Natural Language API 的 API 密钥

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

    转到“凭据”页面

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

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

设置脚本

创建 Apps 脚本项目

  1. 点击下面的按钮,复制以下指标的情感分析: 反馈示例电子表格。Apps 脚本 已附加到该电子表格中。
    复制
  2. 点击附加信息 > Apps 脚本
  3. 使用您的 API 密钥更新脚本文件中的以下变量:
    const myApiKey = 'YOUR_API_KEY'; // Replace with your API key.
  4. 点击“保存”“保存”图标

添加文本数据

  1. 返回到电子表格。
  2. id 列和 comments 列中添加文本数据。您可以使用样本 来自 Kaggle 的度假物业评价 或使用您自己的数据。您可以根据需要添加更多列,但要 那么脚本的 idcomments 中必须具有数据 列。

运行脚本

  1. 在电子表格的顶部,点击情感工具 > 标记实体和情感。您 您可能需要刷新页面才能看到此自定义菜单。
  2. 出现提示时,为脚本授权。 如果 OAuth 同意屏幕显示以下警告:“此应用未经验证”, 选择高级 > 以继续 前往“{Project Name}”(不安全)

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

后续步骤