|
// |
|
// 「このSSに何写ってる?」判定機 |
|
// |
|
// Author: Makopoppo (SL Name: Mako Nozaki) |
|
// |
|
// [使い方] |
|
// |
|
// 1. Microsoft Azureの「Computer Vision API」の無料試用に申し込みます。 |
|
// https://azure.microsoft.com/ja-jp/services/cognitive-services/computer-vision/ |
|
// |
|
// 2. Microsoft Azureの「Translator Text API」の無料試用に申し込みます。 |
|
// https://azure.microsoft.com/ja-jp/services/cognitive-services/translator-text-api/ |
|
// |
|
// 3. 適当なオブジェクトの中にスクリプトを作成し、この内容で上書きします。 |
|
// |
|
// 4. 「ここを変更してください」を、キーやエンドポイントの情報で書き換えて、保存します。 |
|
// |
|
// 5. 判定したいスクリーンショット(SS)を Ctrl + ドラッグ でオブジェクトに入れます。 |
|
// (オブジェクトの縁が赤くなったのを確認してからマウスを離しましょう) |
|
// |
|
// 6. オブジェクトをタッチすると、判定が開始されます。 |
|
// |
|
// チャットとフローティングテキストで、解析結果が表示されます。 |
|
// オブジェクトの所有者がフルパーミッション(他の人の場合、次の所有者の権限がフルパーミッション) |
|
// となるSSを入れたら、オブジェクトのどこか一面にSSが表示されます。 |
|
// 2枚以上同時に入れた場合、フローティングテキストとSS表示は、どれか1枚のみとなります。 |
|
// |
|
// 注意) 2017年現在の技術レベルでは、判定がかなり怪しいようです。 |
|
// あくまでもネタとしてお使いください。 |
|
// |
|
|
|
|
|
// ### ここを変更してください ############################################# |
|
|
|
// 「Computer Vision API」の「キー1」か「キー2」 |
|
string KEY_FOR_COMPUTER_VISION = "XXXXXXXX"; |
|
// 「Computer Vision API」の「エンドポイント」(下記は米国中南部の例) |
|
string ENDPOINT_FOR_COMPUTER_VISION = "https://southcentralus.api.cognitive.microsoft.com/vision/v1.0"; |
|
// 「Translator Text API」の「キー1」か「キー2」 |
|
string KEY_FOR_TRANSLATOR_TEXT = "XXXXXXXX"; |
|
|
|
// #################################################################### |
|
|
|
// レスポンス待ちのリクエスト管理用 [リクエストID, オブジェクト名, ...] のように入っています |
|
list analyzeImageRequests = []; |
|
list translateRequests = []; |
|
|
|
// 現在表示中のSS(これだけは、次にオブジェクトにSSが投げ入れられるまでインベントリに残ります) |
|
string currentDisplayInvName = ""; |
|
|
|
// ### |
|
// ### Computer Vision API を使って画像判定リクエストを送信する |
|
// ### |
|
examine(string invName) |
|
{ |
|
string pictureUUID = llGetInventoryKey(invName); |
|
string url = ENDPOINT_FOR_COMPUTER_VISION + "/analyze?visualFeatures=Description"; |
|
list parameters = [ |
|
HTTP_METHOD, "POST", |
|
HTTP_MIMETYPE, "application/json", |
|
HTTP_BODY_MAXLENGTH, 16384, // デフォルトでは2048バイトまでしか受け取れないので、念のために増やしています |
|
HTTP_CUSTOM_HEADER, "Ocp-Apim-Subscription-Key", KEY_FOR_COMPUTER_VISION |
|
]; |
|
// インワールドのテクスチャは、「http://secondlife.com/app/image/<UUID>/2」で普通に取得できるため、 |
|
// Azureに、このURLを使ってSSを取ってきて判定してもらうようにしています |
|
string body = "{\"url\":\"http://secondlife.com/app/image/" + pictureUUID + "/2\"}"; |
|
key requestId = llHTTPRequest(url, parameters, body); |
|
analyzeImageRequests += [requestId, invName]; |
|
} |
|
|
|
// ### |
|
// ### Translator Text API を使って翻訳リクエストを送信する |
|
// ### |
|
translate(string invName, string caption) |
|
{ |
|
// 翻訳対象テキストのエスケープは必要かどうか不明ですが、念のために実施しています |
|
string url = "https://api.microsofttranslator.com/V2/Http.svc/Translate?appid&text=" + llEscapeURL(caption) + "&to=ja"; |
|
list parameters = [ |
|
HTTP_METHOD, "GET", |
|
HTTP_MIMETYPE, "text/plain;charset=utf-8", |
|
HTTP_BODY_MAXLENGTH, 16384, |
|
HTTP_CUSTOM_HEADER, "Ocp-Apim-Subscription-Key", KEY_FOR_TRANSLATOR_TEXT |
|
]; |
|
key requestId = llHTTPRequest(url, parameters, ""); |
|
translateRequests += [requestId, invName]; |
|
} |
|
|
|
default |
|
{ |
|
state_entry() |
|
{ |
|
llSetText("", <1,1,0.1>, 1.0); |
|
|
|
// 現在オブジェクトの中にあるSSは全て削除しておきます |
|
integer i; |
|
integer invLength = llGetInventoryNumber(INVENTORY_TEXTURE); |
|
for (i = 0; i < invLength; i++) |
|
{ |
|
llRemoveInventory(llGetInventoryName(INVENTORY_TEXTURE, i)); |
|
} |
|
|
|
// 誰でもオブジェクトにドロップできるようにします |
|
llAllowInventoryDrop(TRUE); |
|
} |
|
|
|
// changed()イベントで処理しようかと思ったのですが、 |
|
// 大量にドロップしたりすると2回発生するなどしてAPIカウントが上がるので、やめました |
|
|
|
touch_start(integer num_detected) |
|
{ |
|
// 現在表示しているSSを削除します |
|
if (currentDisplayInvName != "") |
|
{ |
|
llSetText("", <1,1,0.1>, 1.0); |
|
llRemoveInventory(currentDisplayInvName); |
|
currentDisplayInvName = ""; |
|
} |
|
|
|
// 1枚ずつ処理してAzureにリクエストを送信します |
|
integer i; |
|
integer invLength = llGetInventoryNumber(INVENTORY_TEXTURE); |
|
for (i = 0; i < invLength; i++) |
|
{ |
|
string invName = llGetInventoryName(INVENTORY_TEXTURE , i); |
|
examine(invName); |
|
} |
|
} |
|
|
|
http_response(key request_id, integer status, list metadata, string body) |
|
{ |
|
|
|
integer analyze_pos = llListFindList(analyzeImageRequests, [request_id]); |
|
integer translate_pos = llListFindList(translateRequests, [request_id]); |
|
|
|
// Analyze Image APIへのリクエストに対するレスポンスの場合 |
|
if (analyze_pos > -1) |
|
{ |
|
string invName = llList2String(analyzeImageRequests, analyze_pos + 1); |
|
|
|
if (status == 200) |
|
{ |
|
// {description:{captions: [{text: 目当ての文字列 }]}} |
|
// のような感じのbodyになっています |
|
string caption = llJsonGetValue(body, ["description", "captions", 0, "text"]); |
|
// 2017.12時点でComputer Vision APIは日本語に対応していないので、 |
|
// 英語で返ってきた結果をTranslator Text APIに投げて日本語化します |
|
//llOwnerSay(caption); // 原文を見たい方は、ここのコメントアウトを外してください |
|
translate(invName, caption); |
|
} |
|
else |
|
{ |
|
llSay(0, invName + "をComputer Vision APIで解析する際にエラーが発生しました。"); |
|
llSay(0, "HTTP Status: " + (string)status + " " + body); |
|
} |
|
analyzeImageRequests = llDeleteSubList(analyzeImageRequests, analyze_pos, analyze_pos + 1); |
|
} |
|
// Translator Text APIへのリクエストに対するレスポンスの場合 |
|
else if (translate_pos > -1) |
|
{ |
|
string invName = llList2String(translateRequests, translate_pos + 1); |
|
|
|
if (status == 200) |
|
{ |
|
// >までをカットしてから、<の前までをくり抜いて、表示させています |
|
integer start_pos = llSubStringIndex(body, ">"); |
|
string work = llDeleteSubString(body, 0, start_pos); |
|
integer end_pos = llSubStringIndex(work, "<"); |
|
string translatedText = llGetSubString(work, 0, end_pos - 1); |
|
llSay(0, "「" + invName + "」には 「" + translatedText + "」が写っているようです。"); |
|
|
|
// これまで表示されていた画像を、インベントリから消します |
|
// (この時点で、貼られていたテクスチャは消えます) |
|
if (currentDisplayInvName != "") |
|
{ |
|
llRemoveInventory(currentDisplayInvName); |
|
currentDisplayInvName = ""; |
|
} |
|
|
|
// 解析したSSをオブジェクト表面に貼り付けます |
|
// SSがフルパーミッションでないと貼り付ける際にエラーが発生するため、事前にチェックします |
|
integer permDesired = (PERM_COPY|PERM_MODIFY|PERM_TRANSFER); |
|
if ((permDesired & llGetInventoryPermMask(invName, MASK_OWNER)) == permDesired) |
|
{ |
|
llSetTexture(llGetInventoryKey(invName), 1); |
|
currentDisplayInvName = invName; |
|
} |
|
else |
|
{ |
|
// 貼り付けられない場合は、SSは不要なため削除します |
|
llRemoveInventory(invName); |
|
} |
|
|
|
// 貼り付け可不可に関わらず、フローティングテキストに解析結果を表示します |
|
llSetText(translatedText, <1,1,0.1>, 1.0); |
|
} |
|
else |
|
{ |
|
llSay(0, invName + "Translator Text APIで解析する際にエラーが発生しました。"); |
|
llSay(0, "HTTP Status: " + (string)status + " " + body); |
|
} |
|
translateRequests = llDeleteSubList(translateRequests, translate_pos, translate_pos + 1); |
|
} |
|
} |
|
} |