Pepperスキルの台本をスプレッドシートで作成してSayTextを直接台本から読み込む

# 使うもの
- Google SpreadSheet
- Google Apps Script
- Choregraphe
- Pepper

# 説明
Pepperの台本を作る時、Excel等を使用していましたが複数人で開発する時やブラウザ上で場所を選ばずに作りたいのでGoogle SpreadSheetを使うようになりました。
僕は会話の調整を行ったものも台本に一緒に入力して保存しておくのでいちいちコピペしたり、配布済みのパッケージにアップデートをかけるのがめんどくさいので台本からそのまま読み込む事が出来るようにしました。

ので、メモとして各項目毎に記載していきます。
## Google SpreadSheet

僕はこんな感じで台本を作っています。

<img width="1657" alt="スクリーンショット 2016-06-23 22.07.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/56585/bda3f0f0-611b-1802-836f-8376fd1b659e.png">


左から

1. ID
- ダイアログボックスの名前
- ディスプレイに表示するページの名前
- 条件
- ボタン
- モーションの番号や種類
- セリフ（人語）
- セリフ（ぺパ語）

スキルの内容によって項目は多少変わったりすることもありますが、基本はこんな感じで台本を作っています。
台本を作ったらSpreadSheetのURLの中にある「**https : //docs.google.com/spreadsheets/d/**」の後にある「**XXXXXXXXXXXXXXXX(Book ID)**」とその後にある「**/edit#gid=**」の後ろの数字「**1234567(Sheet ID)**」をメモしておきます。
これらはChoregrapheからリクエストを送る時に使用します。

## Google Apps Script

```js:SayText.gs
//エラーが起きた時に送るメールアドレス
var managerAddr = "hoge@xxxx.co.jp";


function doGet(e) {
  //param1という名前のパラメータを受け取る。
  var json = JSON.parse(e.parameter.param1);
  //パラメータのBookIDのスプレッドシートを開く
  var ss = SpreadsheetApp.openById(decodeURI(json["sayDb_id"]));
  //開いたスプレッドシートにあるシート取得
  var sheets = ss.getSheets();
  
  for (var i in sheets){
    var sheet = sheets[i];
    //パラメータで指定したシートIDを見つけたら処理を開始
    if (sheet.getSheetId() == json["db_id"]){
      var say_txt = getSayTxt(sheet);
    }
  }
  //jsonで返す
  return ContentService.createTextOutput(JSON.stringify(say_txt)).setMimeType(ContentService.MimeType.JSON);
}

function getSayTxt(sheet) {
  var sCol = 1;
  var sRow = 2;
  var lRow = sheet.getLastRow();
  
  //1行目が"id"という名前がついてる列を探す
  var sayIdCol = getSayTxtCol(sheet, "id");
  //同様に"pepaLanguage"という名前がついてる列を探す
  var sayTxtCol = getSayTxtCol(sheet, "pepaLanguage");
  //見つからなかったらエラーで返す。
  if (sayTxtCol == 0 || sayIdCol == 0){
    GMailApp.sendMail(managerAddr, "getSay実行時", "列が見つからないシートがあるようです。" + sheet.getSheetId());
    Logger.log("Columns is not found");
    return [];
  }
  
  //"id"と"pepaLanguage"の位置を確認しておかしなことにならないようにしてる。
  if (sayIdCol > sayTxtCol){
    var data = sheet.getRange(sRow, sayTxtCol, lRow, sayIdCol).getValues();
  }else{
    var data = sheet.getRange(sRow, sayIdCol, lRow, sayTxtCol).getValues();
  }
  var json = new Object();
  var jsonArray = [];
  //追加していく
  for (var i = 0; i < data.length -1; i++){
    var val = data[i][sayIdCol - 1];
    if (val != "" && val != null){
      json[String(data[i][sayIdCol - 1])] = data[i][sayTxtCol - 1];
    }
  }
  jsonArray.push(json);
  return jsonArray;
}
  
function getSayTxtCol(sheet, title){
  var lCol = sheet.getLastColumn();
  for (var i = 1; i <= lCol; i++){
    if (sheet.getRange(1, i).getValue() == title){
      return i;
      break;
    }
  }
  return 0;
}
```

## Choregraphe (Python)
Pythonの方は見ればわかると思います。

```py:LoadSayText.py
class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)

    def onLoad(self):
        self.memory = ALProxy("ALMemory")

    def onUnload(self):
        self.memory = None

    def onInput_onStart(self):
        import urllib, urllib2, json
        #パラメータを作る。
        #実際のアプリ内ではメモリで渡してる。
        p = {
            "sayDb_id":XXXXXXXXXXXXXXXX(Book ID),
            "db_id":1234567(Sheet ID)
            }
        data ={}

        try:
            data['param1'] = json.dumps(p)
            url_values = urllib.urlencode(data)
            full_url = '%s?%s' % url(apiのURL), url_values)
            request = urllib2.urlopen(full_url)
            self.json = json.loads(request.read(), "utf-8")[0]

            if len(self.json) == 0:
                self.onNotFound()
                return
            #返ってきた値をメモリに保存する。
            #保存したTextはSayBoxで呼び出して喋らせる。
            for key, value in self.json.items():
                self.memory.insertData("SayText/%d" % int(key), value.encode('utf-8'))
            self.onStopped()
        except Exception as e:
            self.logger.warn('==========エラー内容==========')
            self.logger.warn(e)
            self.logger.warn('============================')
            self.onError()
```

### 終わり
書いててちょっとエラーが起こりそうなとこを見つけました。