【오래된 기사입니다】 작은 재료 - Watson API/Node.js에서 콜백 (또는 Promise)을 의식하지 않고 API를 순차적으로 실행하는 코드를 작성하는 방법

16733 단어 BluemixibmcloudWatson
(2019/06/12) 이 기사에 있는 promisify를 사용하는 방법은 Watson SDK V3까지의 오래된 정보입니다. 2019/3월에 나온 SDK V4에서는 보다 간단하게 되었으므로, 최신의 V4를 사용할 예정인 분은 기사 작은 자료 : Watson SDK V4 (Node.js)를 사용하면 더 쉽게 콜백 (또는 Promise)을 의식하지 않고 API를 호출 할 수 있습니다. 」쪽을 참조해 주세요.

예를 들어 "Assistant의 응답 확신도가 기준값 이하인 경우, Discovery에서 긴 꼬리를 검색하여 답변을 제시"등 여러 Watson API를 동기적으로/순차적으로 호출하고 싶을 수 있습니다.



석가설이지만 Node.js 환경은 비동기 실행 환경이므로 이런 일을하고 싶은 경우의 코드에서는 콜백이나 Promise를 사용해야합니다. 하지만 Promise는 직관적이지 않고, 어쩐지 귀찮다고 생각하고 있었습니다 1 에서 StackOverflow에서 다음 항목을 발견했습니다.

Using Async/Await in WATSON Nodejs SDK
How can I promisify Watson Assistant functions to allow async/await in node?

요점은 Node.js의 V8에서는 promisify가 표준으로 탑재되어 쉽게 비동기를 의식하지 않는 코드를 쓸 수 있다.그렇습니다만, 이 기구가 Watson API에서도 이용할 수 있습니다. 예를 들어 다음과 같은 느낌으로 WatsonAssistant의 인스턴스의 "message"API를 promisify로 와서 await로 호출하면 Watson 측에서 처리가 완료 될 때까지 제어가 대기 상태가되고 완료 후 프로그램으로 제어가 돌아갑니다 = 동기화 적인 코딩이 가능합니다. (비동기의 까다로운 코드가 필요하지 않습니다)
const messagePromise = util.promisify(assistant.message);var response = await messagePromise.call(assistant, params);
아래는 "Assistant에 묻고 확신도가 기준치를 밑돌면 Discovery에 다시 묻는다"시나리오의 간단한 샘플입니다만, 동기적인=알기 쉬운 코드가 실현되고 있는 것을 볼 수 있다고 생각합니다. 2

app.js
'use strict';
/*
    Watson Assistant & Watson Discoveryをpromisifyを使って逐次実行
*/
/* ibmcloud上のnode.jsで実行するならここをコメントアウト
const express = require('express');
const app = express();
const port = process.env.PORT || 8080;
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(port, () => console.log('Example app listening on port %d', port));
*/
const util = require('util');

console.log('==== start=======');
const assistant_iam_apikey ='xxxxxxxxxxxxxx';
const assistant_url ='https://gateway-syd.watsonplatform.net/assistant/api';
const assistant_workspace_id = 'xxxxxxxxxxxx';

const discovery_iam_apikey ='xxxxxxxxxxxxxx';
const dicovery_iam_url ='https://gateway-syd.watsonplatform.net/discovery/api';
const discovery_collection_id ='xxxxxxxxxxxxxx';
const discovery_configuration_id ='xxxxxxxxxxxxxx';
const discovery_environment_id = 'xxxxxxxxxxxxxx';

var AssistantV1 = require('watson-developer-cloud/assistant/v1');
var assistant = new AssistantV1({
    version: '2018-09-20',
    iam_apikey: assistant_iam_apikey,
    url: assistant_url
});

var DiscoveryV1 = require('watson-developer-cloud/discovery/v1');
const discovery = new DiscoveryV1({
  url: dicovery_iam_url,
  version: '2018-10-15',
  iam_apikey: discovery_iam_apikey
});

// Assistant
async function message(text) {
    console.log("message Start:[" + text + "]")
    var params = {
        input: { text: text },
        workspace_id: assistant_workspace_id
    };
    const messagePromise = util.promisify(assistant.message);
    var response = await messagePromise.call(assistant, params);
    return response;
}

// Discovery
async function query(text) {
    console.log("query Start:[" + text + "]")
    var params = {
        environment_id: discovery_environment_id,
        collection_id: discovery_collection_id,
        passages: true,
        passages_count: 1,
        natural_language_query: text
    };
    const queryPromise = util.promisify(discovery.query);
    var response = await queryPromise.call(discovery, params);
    return response;
}

//***********************************************
//  Promise/非同期を意識したコードを書かずに済んでます
//***********************************************
async function main() {
    var min_confidence = 0.6; // 求める確信度。これを下回ったらDiscoveryに聞きなおす
    var text = 'Excelで表の必要な部分だけを印刷するにはどうすればいいでしょうか';

    var response = await message(text);
    console.log('confidence of Assistant:',
            JSON.stringify(response.intents[0].confidence, null, 2));

    if (response.intents[0].confidence < min_confidence ){
        // Assistantの回答の確信度が所定の基準を下回ったらDiscoveryにて再度検索
        var response = await query(text);
        console.log('message response from Discovery:',
            JSON.stringify(response.passages, null, 2));        
    } else {
        // Assistantの回答の確信度が所定の基準以上ならAssistantの回答を提示
        console.log('message response from Assistant:',
            JSON.stringify(response.output.text[0], null, 2));
    }
}

main()


다음은 실행 결과의 예입니다.
==== start=======
message Start:[Excelで表の必要な部分だけを印刷するにはどうすればいいでしょうか]
confidence of Assistant: 0.504277801513672
query Start:[Excelで表の必要な部分だけを印刷するにはどうすればいいでしょうか]
message response from Discovery: [
  {
    "document_id": "673b0e32529bf4c614c15acaebb47bab",
    "passage_score": 40.21290429830693,
    "passage_text": "Excelでは、印刷対象を選択して、必要な部分だけを印刷することができます。ここでは
、ご使用のExcelのバージョンに応じた参照先を案内します。\n\n対処方法\n\nExcelで表の必要な部分だけを印
刷する方法については、以下の情報を参照してください。\n※ ご使用のExcelのバージョンに応じた項目をクリ
ックしてください。\n\nExcel 2013の場合\nExcel 2013で表の必要な部分だけを印刷する方法\n\nExcel 2010の
場合\nExcel 2010で表の必要な部分",
    "start_offset": 762,
    "end_offset": 998,
    "field": "text"
  }
]

이상입니다.



그럼 Python이라든지 다른 언어 사용하면 좋지 않을까, 라는 츳코미도 있습니다만. 3

코딩의 관점에서 동기적인 이미지로 솔직하게 쓸 수 있다는 것만으로 내부적으로는 비동기/Promise의 기구를 사용하고 있습니다.

이야기를 단순화하기 위해 코드는 nodejs 환경에서 js를 일괄 적으로 실행하는 형태로 만듭니다. 실제로 Watson_API 호출은 AP 서버 환경에서 app.get, app.post 등의 요청을 받으면 사용할 수 있습니다.

좋은 웹페이지 즐겨찾기