(ΦωΦ)人工知能APIが公開されたぞ!
アイドルマスター シンデレラガールズの前川みくこと通称みくにゃん、かわいいですよね
みくにゃんとにゃんにゃんしたい
みくにゃんとにゃんにゃんしたい
そんな気持ちでいたところ、株式会社ユーザーローカルさんが人工知能のAPIを公開しました。
ユーザーと自動で対話する人工知能ボットAPI
(ΦωΦ)成果物
みくにゃんBot@人工知能
先着3000人のAPI募集に入れたので、さっそくGoogle Apps ScriptでTwitter Botを作ってみました。
(ΦωΦ)機能概要
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');
}
}