LoginSignup
20
18

More than 5 years have passed since last update.

【アタシポンコツ】人工知能で前川みくBotをつくる【アンドロイド】

Last updated at Posted at 2016-06-17

(ΦωΦ)人工知能APIが公開されたぞ!

アイドルマスター シンデレラガールズの前川みくこと通称みくにゃん、かわいいですよね
みくにゃんとにゃんにゃんしたい
みくにゃんとにゃんにゃんしたい

そんな気持ちでいたところ、株式会社ユーザーローカルさんが人工知能のAPIを公開しました。
ユーザーと自動で対話する人工知能ボットAPI

ん…??
talk_cat.jpg
みくにゃんだ…
これはみくにゃんが創れるぞ…っ!

(ΦωΦ)成果物

みくにゃんBot@人工知能
先着3000人のAPI募集に入れたので、さっそくGoogle Apps ScriptでTwitter Botを作ってみました。
cad0e8e6-9461-9203-e65a-8d6ad134102a.png

(ΦωΦ)機能概要

1.10分ごとにメンションを取得
2.返信をユーザAPIで生成
3.ニックネームをAPIで取得(※Twitterの名前ベースなので取れない可能性大)
4.みくにゃん語にコンパイル
5.メンションに返信してくれる

(ΦωΦ)使用したAPI

自動会話API

送られたメッセージへの返信を取得できます。
LINEのりんなちゃんのイメージです。

キャラクター会話変換API

メッセージの口調を変換して取得できます。
現在は「猫」「犬」「老人」に対応しています。

氏名自動識別API

名前から「姓」「名」「姓(よみ)」「名(よみ)」「性別」「ニックネーム一覧」が取得できます。

(ΦωΦ)免責

Twitter APIやユーザーローカルのAPI制限は意識していません
ソースをそのまま使用する際はご注意ください

(ΦωΦ)ソース

MikunyanBot.gs
// Twitterの認証キー
var CONSUMER_KEY = '{TwitterのCONSUMER KEY}';
var CONSUMER_SECRET = '{TwitterのCONSUMER SECRET}';

var USERLOCAL_API_KEY = 'sample'; // UserLocalのAPIキー
var TWITTER_ID = '@MikunyanUL'; // BotのTwitter ID

// リプライ済みシート
var MENTIONED_SHEET_URL = 'https://docs.google.com/spreadsheets/d/{ドキュメントのID}/edit#gid=0';
var MENTIONED_SHEET;
var ALL_MENTIONED_ID; // リプライ済みID一覧

// 直近100件へリプライをする
function replyAll() {

  // リプライ済み一覧の読み込み
  initReplied();

  // すべてのメンションを取得
  var mentions = getTwitterMentions();
  for each (mention in mentions) {
    // ツイート情報を取得
    var screenName = mention.user.screen_name;
    var name = mention.user.name;
    var text = mention.text.replace(TWITTER_ID, '').trim();
    var mentionID = mention.id_str;

    // リプライ済みならスキップ
    if ( hasReplied(mentionID) ) continue;

    // 人工知能のメッセージを取得
    var message = getReplyCatMessage(screenName, name, text);

    // リプライ
    tweetText(message, mentionID);

    // リプライ済みID一覧に記録
    MENTIONED_SHEET.appendRow([mentionID]);
  }
}

// リプライ済みデータをスプレッドシートから読み込み
function initReplied() {
 var ss = SpreadsheetApp.openByUrl(MENTIONED_SHEET_URL);
 MENTIONED_SHEET = ss.getSheets()[0];

 var lastRow = MENTIONED_SHEET.getLastRow();
 if (lastRow == 0) {
   ALL_MENTIONED_ID = [];
   return;
 }

 // データクリーン
 if (lastRow > 200) {
   MENTIONED_SHEET.deleteRows(0, 100);
   lastRow = MENTIONED_SHEET.getLastRow();
 }

 var cell = MENTIONED_SHEET.getRange("A1");
 var allValue = cell.offset(0, 0, lastRow);
 ALL_MENTIONED_ID = allValue.getValues().map(function(v) { return v[0] });
}

/**
 * リプライ済みツイートかチェック
 * @mentionID 返信先のツイートID
 */
function hasReplied(mentionID) {
 var index = ALL_MENTIONED_ID.indexOf(mentionID);
 if (index > -1) return true;
 return false;
}

/**
 * ツイートする
 * @text ツイートする文章
 * @mentionID 返信先のツイートID
 */
function tweetText(text, mentionID) {                         
  var service = getService();
  if (service.hasAccess()) {
    var url = 'https://api.twitter.com/1.1/statuses/update.json';
    var payload = {
      status: text,
      in_reply_to_status_id: mentionID
    };
    payload = Object.keys(payload).map(function(key) {
      return encodeRfc3986(key) + '=' + encodeRfc3986(payload[key]);
    }).join('&');
    var response = service.fetch(url, {
      method: 'post',
      payload: payload,
      escaping: false
    });
    var result = JSON.parse(response.getContentText());
    Logger.log(JSON.stringify(result, null, 2));
  } else {
    var authorizationUrl = service.authorize();
    Logger.log('URLにアクセスし認証してください: %s',
        authorizationUrl);
  }
}

// メンション一覧を取得する
function getTwitterMentions() {                         
  var service = getService();
  if (service.hasAccess()) {
    var url = 'https://api.twitter.com/1.1/statuses/mentions_timeline.json';
    var response = service.fetch(url + '?count=200');
    var result = JSON.parse(response.getContentText());
    return result;
  } else {
    var authorizationUrl = service.authorize();
    Logger.log('URLにアクセスし認証してください: %s',
        authorizationUrl);
  }
}

// 返信メッセージを生成
function getReplyCatMessage(screenName, name, message) {

  // ニックネーム アカウント名が(姓)(名)じゃないと上手くいきにくい
  var nickname = getNickname(name);

  // メッセージ生成
  var normalMessage = getReplyMessage(message);
  normalMessage = normalMessage.replace(/[\.\??!ー]/g, ''); // 語尾に記号があるとキャラクター変換されないことがある
  var catMessage = (normalMessage ? convertMessage(normalMessage, 'cat') : normalMessage);

  // 返信メッセージ作成
  var replyMessage = '@' + screenName + ' ';
  replyMessage += (nickname ? nickname + '' : '');
  replyMessage += catMessage;
  return replyMessage;
}

// 人工知能による返信メッセージ取得
function getReplyMessage(message) {
  // 自動会話API
  var url = 'https://chatbot-api.userlocal.jp/api/chat';
  url += '?message=' + encodeRfc3986(message);
  url += '&key=' + USERLOCAL_API_KEY;

  // API結果取得
  var response = UrlFetchApp.fetch(url);
  var apiResult = JSON.parse(response.getContentText());
  if (apiResult.status != 'success') return;
  return apiResult.result;
}

// 指定したタイプの話し方に変更
function convertMessage(message, characterType) {
  // キャラクター会話変換API
  var url = 'https://chatbot-api.userlocal.jp/api/character';
  url += '?message=' + encodeRfc3986(message);
  url += '&character_type=' + characterType // 猫:cat 犬:dog 老人:roujin
  url += '&key=' + USERLOCAL_API_KEY;

  // API結果取得
  var response = UrlFetchApp.fetch(url);
  var apiResult = JSON.parse(response.getContentText());
  if (apiResult.status != 'success') return;
  return apiResult.result;
}

// Twitter名からニックネームを取得
// ※取れないこともあり
function getNickname(name) {
  // 氏名自動識別API 
  var url = 'https://chatbot-api.userlocal.jp/api/name';
  url += '?name=' + encodeRfc3986(name);
  url += '&key=' + USERLOCAL_API_KEY;

  // API結果取得
  var response = UrlFetchApp.fetch(url);
  var apiResult = JSON.parse(response.getContentText());
  if (apiResult.status != 'success') return;
  var result = apiResult.result;

  // 「名」「名(読み)」が取得できる → ニックネーム返却
  // ※「名」がないデータはニックネームの精度がまだ良くないため
  if (!result.first_name) return;
  if (!result.first_name_yomi) return;

  // ニックネームを候補からランダムに取得
  var nicknames = result.nickname;
  var nickname = nicknames[Math.floor(Math.random() * nicknames.length)];
  return nickname;
}

(ΦωΦ)ソース(Twitter API用)

MikunyanBot.gs
/**
 * Encodes a string using the RFC 3986 spec.
 */
function encodeRfc3986(str) {
  return encodeURIComponent(str).replace(/[!'()]/g, function(char) {
    return escape(char);
  }).replace(/\*/g, "%2A");
}

/**
 * Reset the authorization state, so that it can be re-tested.
 */
function reset() {
  var service = getService();
  service.reset();
}

/**
 * Configures the service.
 */
function getService() {
  return OAuth1.createService('Twitter')
      // Set the endpoint URLs.
      .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
      .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
      .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')

      // Set the consumer key and secret.
      .setConsumerKey(CONSUMER_KEY)
      .setConsumerSecret(CONSUMER_SECRET)

      // Set the name of the callback function in the script referenced
      // above that should be invoked to complete the OAuth flow.
      .setCallbackFunction('authCallback')

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getUserProperties());
}

/**
 * Handles the OAuth2 callback.
 */
function authCallback(request) {
  var service = getService();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success!');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}

参考記事

Google Apps ScriptでTwitter botを作ってみた

20
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
18