티스토리 뷰

공식 다큐먼트 링크 :

https://developers.google.com/actions/dialogflow/first-app



오류 발생

따라하다가 보면 오류가 생긴다. v2 invalid argument 라고...




이유

stackoverflow에서 오류의 원인을 찾으면  [stackoverflow 클릭하면 사이트로!]

1. end conversation 클릭을 안해주었거나 등 예제를 따라하면서 설정을 안해준 것에서 오류가 날 수 도 있지만 

2. 가장 큰 근본적인 원인은 v2 베타 버전이 나왔고 그에 맞게 적어주는 형식이 달라졌는데 이에 맞게 적어주지 않아서 같다.



헷갈렸던 v1, v2 


중요했던 것은 Dialogflow fulfillment beta api1 api2 와 Actions on google v1, v2 에 있었다.

둘은 다른 것이었고


위에서 v2에 오류였던 것은 바로 Actions on Google v2 문제였다.

이에 대한 공식 문서는 다음을 참조 : https ://developers.google.com/actions/reference/v1/migration 


요점은 

2017년 5월 17일 이후 v2 버전으로 업데이트, 기본적으로 지원해주는 것은 v2 이다.

v1도 일년동안 지원해줄 것이나 가능한 한 빨리 전에 v1으로 짰던 코드를 v2로 짜길 바란다!


달라진 것

1. snake case 에서 Camel case로 바뀌었다. 예를 들면 input_data 들로 썼던 것을 이제는 inputData 로 적게 되었다.

2. node.js client library 에서 제공해주는 예를 들면, 사용자에게 퍼미션 얻는 거라던가, 업데이트 등록하는 것, 위치,시간 정보 얻는 기능들을 제공해주는 system intent 가 spec 으로 제공해주었었는데 이제는 data 형식으로 사용한다. 

(이부분은 일단 아직 감이 안잡혀서 push 알림 만드는 예제에서 더 알아낼 생각이다.)

3. 제공해주던 Permission_request 와 is_ssml 이 이제는 안되나보다


이것보다 중요한 것은 바로 버전을 업데이트 하는 것이었다...! 




왜냐하면 공식 문서의 작성방식은 version 1 이기 때문이고 


 firebase enline editor 의 글은 v2 에 맞추어져있기 떄문인 것 같다. 


하지만 나는 오디오 스피치를 사용하기 위해 v2 방식을 써야했고 그렇기 때문에 



초간단 해결 (업데이트만 해주면 됨!)

 업데이트 하는 것이었다...! 

그래서 공식 예제 문서에 package.json 을 보면


{
 
"name": "silly-name-maker",
 
"description": "Find out your silly name!",
 
"version": "0.0.1",
 
"author": "Google Inc.",
 
"engines": {
   
"node": "~4.2"
 
},
 
"dependencies": {
   
"actions-on-google": "^1.0.0",
   
"firebase-admin": "^4.2.1",
   
"firebase-functions": "^0.5.7"
 
}
}

1. actions on google 버전이 1.0.0 으로 되어있는데 이것을 1.1.0 버전으로 올리고

npm install 을 커멘드 창에서 치면 된다!  (만약에 공식 문서대로 npm 툴 깔고, firebase init 해서 커맨드 창에서 개발을 하고 있었다면!)


2. 만약 fulfillment inline editor 아래 사진과 같은 곳에서 개발 하고 있었다면


index.js 공식문서와 똑같이 복붙! - 단, 중간에 exports.sillyNameMaker = 이부분을 exports.dialogflowFirebaseFulfillment 로 바꾸어준다.

package.json 에서 공식문서와 똑같이 복붙, 1. 과 같이 버전을 1.1.0으로 바꾸어준다.

deploy 끝!


---------------------------------------------------------------------------------------------------------------------------------------------------------

위에서는 actions on google에 v1 ,v2 에 관한 이야기였다.


내가 헷갈렸던 것은 Dialogflow fulfillment beta api v1, v2 였다.

이에 관한 공식문서는 

https://dialogflow.com/docs/reference/v2-comparison 여기서 확인 할 수 있다.


actions on google 문서에서 위와 같이 말하길래, Dialogflow's fulfillment api v2 를 사용하면


app. ask, app.tell 등을 사용한 공식문서 코드에서 오류가 날 줄 알았는데,

Dialogflow's fulfillment api v2 를 사용해도 공식문서에 app.tell app.ask 로 이루어진 전체 코드를 사용해도 문제가 없었다.

현재는 지원해주는 것이려나..?



아래는 Dialogflow's fulfillment api v1, v2 문제 때문에 안되는 것인 줄 알고, app.ask , app.tell 코드를 다 빼고 적은 코드로 해결했던 것!


결론적으로 actions on google에 v1 이 아니라 v2 여야 하고, 그러기 위에서 dependencies 만 버전을 올려줬으면 오류가 안나는 거였다~



해결(막 Dialogflow 시작했을 때 야매로 )


//공식 예제 원본

'use strict';

process.env.DEBUG = 'actions-on-google:*'; const App = require('actions-on-google').DialogflowApp; const functions = require('firebase-functions');

// a. the action name from the make_name Dialogflow intent const NAME_ACTION = 'make_name'; // b. the parameters that are parsed from the make_name intent const COLOR_ARGUMENT = 'color'; const NUMBER_ARGUMENT = 'number';

exports.sillyNameMaker = functions.https.onRequest((request, response) => { const app = new App({request, response}); console.log('Request headers: ' + JSON.stringify(request.headers)); console.log('Request body: ' + JSON.stringify(request.body));

// c. The function that generates the silly name function makeName (app) { let number = app.getArgument(NUMBER_ARGUMENT); let color = app.getArgument(COLOR_ARGUMENT); app.tell('Alright, your silly name is ' + color + ' ' + number + '! I hope you like it. See you next time.'); } // d. build an action map, which maps intent names to functions let actionMap = new Map(); actionMap.set(NAME_ACTION, makeName);

app.handleRequest(actionMap); });


바꾸어줄 부분


다음과 같은 내용을 바꾸어 적어주어야만 했다. 


0. agent 설정에서 dialog v2 beta api 설정을 on 해주었다.


1. Fulfillment 탭으로 간다.



2. Inline Editor 창에 function precessv2Request 부분으로 간다. (Dialogflow v2 에 맞는 답변을 제시해주는 곳)



3. actionHandlers 에 가서 make_name 액션을 만들어주고 그 액션에 맞는 답변 내용을 생성해준다.

이 부분에 가서 


make_name 액션 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'make_name': () => {  let responseToUser = {
 
        //fulfillmentMessages: richResponsesV2, // Optional, uncomment to enable
 
        //outputContexts: [{ 'name': `${session}/contexts/weather`, 'lifespanCount': 2, 'parameters': {'city': 'Rome'} }], // Optional, uncomment to enable
 
        fulfillmentText: 'Alright, your silly name is ' +
 
      parameters.color + ' ' + parameters.number +
 
      '! I hope you like it. See you next time' 
 
      };
 
      sendResponse(responseToUser);
 
    },
cs



간략 설명


make_name 이라는 action을 추가해주고

실행해야 할 코드에


기존(공식 예제)에서 COLOR_ARGUMENT = color 라고 미리 설정해주고 코드에서 

name is ' + color + 라고 쓰던 것을 (number 도 같은 원리)


const COLOR_ARGUMENT = 'color';


let color = app.getArgument(COLOR_ARGUMENT);


app.tell('Alright, your silly name is ' + color + ' ' +



v2 버전에서는 

Dialogflow 에서 parameter name 과 parameter value를 설정해주었기 때문에


그냥 action 답변부분에서 name is' + parameters.color 라고 사용하면 된다!


즉, 

기존(공식 예제)에서

1. 다음부분 작성 생략 


const COLOR_ARGUMENT = 'color';


let color = app.getArgument(COLOR_ARGUMENT);



2. 'make_name' 새로 작성한 action을 아래와 같은 기존 코드를 바꾸면 된다.

app.tell('Alright, your silly name is ' + color + ' ' + number + '! I hope you like it. See you next time.'); }


color 를 ---- parameters.color 로

number를 ---- parameters.number 로 바꾸어서


 'make_name': () => {  let responseToUser = {
        
        fulfillmentText: 'Alright, your silly name is ' +
      parameters.color + ' ' + parameters.number +
      '! I hope you like it. See you next time' 
      };
      sendResponse(responseToUser);
    }




v2 부분 코드 전체 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Function to handle v2 webhook requests from Dialogflow
*/
function processV2Request (request, response) {
  // An action is a string used to identify what needs to be done in fulfillment
  let action = (request.body.queryResult.action) ? request.body.queryResult.action : 'default';
  // Parameters are any entites that Dialogflow has extracted from the request.
  let parameters = request.body.queryResult.parameters || {}; // https://dialogflow.com/docs/actions-and-parameters
  // Contexts are objects used to track and store conversation state
  let inputContexts = request.body.queryResult.contexts; // https://dialogflow.com/docs/contexts
  // Get the request source (Google Assistant, Slack, API, etc)
  let requestSource = (request.body.originalDetectIntentRequest) ? request.body.originalDetectIntentRequest.source : undefined;
  // Get the session ID to differentiate calls from different users
  let session = (request.body.session) ? request.body.session : undefined;
  // Create handlers for Dialogflow actions as well as a 'default' handler
  const actionHandlers = {
    // The default welcome intent has been matched, welcome the user (https://dialogflow.com/docs/events#default_welcome_intent)
    'input.welcome': () => {
      sendResponse('Hello, Welcome to my Dialogflow agent!'); // Send simple response to user
    },
    // The default fallback intent has been matched, try to recover (https://dialogflow.com/docs/intents#fallback_intents)
    'input.unknown': () => {
      // Use the Actions on Google lib to respond to Google requests; for other requests use JSON
      sendResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
    },
     'make_name': () => {  let responseToUser = {
        //fulfillmentMessages: richResponsesV2, // Optional, uncomment to enable
        //outputContexts: [{ 'name': `${session}/contexts/weather`, 'lifespanCount': 2, 'parameters': {'city': 'Rome'} }], // Optional, uncomment to enable
        fulfillmentText: 'Alright, your silly name is ' +
      parameters.color + ' ' + parameters.number +
      '! I hope you like it. See you next time' 
      };
      sendResponse(responseToUser);
    },
    // Default handler for unknown or undefined actions
    'default': () => {
      let responseToUser = {
        //fulfillmentMessages: richResponsesV2, // Optional, uncomment to enable
        //outputContexts: [{ 'name': `${session}/contexts/weather`, 'lifespanCount': 2, 'parameters': {'city': 'Rome'} }], // Optional, uncomment to enable
        fulfillmentText: 'This is from Dialogflow\'s Cloud Functions for Firebase editor! :-)'// displayed response
      };
      sendResponse(responseToUser);
    }
  };
  // If undefined or unknown action use the default handler
  if (!actionHandlers[action]) {
    action = 'default';
  }
  // Run the proper handler function to handle the request from Dialogflow
  actionHandlers[action]();
  // Function to send correctly formatted responses to Dialogflow which are then sent to the user
  function sendResponse (responseToUser) {
    // if the response is a string send it as a response to the user
    if (typeof responseToUser === 'string') {
      let responseJson = {fulfillmentText: responseToUser}; // displayed response
      response.json(responseJson); // Send response to Dialogflow
    } else {
      // If the response to the user includes rich responses or contexts send them to Dialogflow
      let responseJson = {};
      // Define the text response
      responseJson.fulfillmentText = responseToUser.fulfillmentText;
      // Optional: add rich messages for integrations (https://dialogflow.com/docs/rich-messages)
      if (responseToUser.fulfillmentMessages) {
        responseJson.fulfillmentMessages = responseToUser.fulfillmentMessages;
      }
      // Optional: add contexts (https://dialogflow.com/docs/contexts)
      if (responseToUser.outputContexts) {
        responseJson.outputContexts = responseToUser.outputContexts;
      }
      // Send the response to Dialogflow
      console.log('Response to Dialogflow: ' + JSON.stringify(responseJson));
      response.json(responseJson);
    }
  }
}
const richResponseV2Card = {
  'title''Title: this is a title',
  'subtitle''This is an subtitle.  Text can include unicode characters including emoji 📱.',
  'imageUri''https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
  'buttons': [
    {
      'text''This is a button',
      'postback''https://assistant.google.com/'
    }
  ]
};
const richResponsesV2 = [
  {
    'platform''ACTIONS_ON_GOOGLE',
    'simple_responses': {
      'simple_responses': [
        {
          'text_to_speech''Spoken simple response',
          'display_text''Displayed simple response'
        }
      ]
    }
  },
  {
    'platform''ACTIONS_ON_GOOGLE',
    'basic_card': {
      'title''Title: this is a title',
      'subtitle''This is an subtitle.',
      'formatted_text''Body text can include unicode characters including emoji 📱.',
      'image': {
        'image_uri''https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png'
      },
      'buttons': [
        {
          'title''This is a button',
          'open_uri_action': {
            'uri''https://assistant.google.com/'
          }
        }
      ]
    }
  },
  {
    'platform''FACEBOOK',
    'card': richResponseV2Card
  },
  {
    'platform''SLACK',
    'card': richResponseV2Card
  }
];
 
cs




그러면 성공!








v2 parameters


v2 에서 parameter를 불러오는 방법을 찾는데 가장 시간이 오래 걸렸다.


도움을 주었던 참고자료


Dialogflow 에서 parameter를 전송하는 것에 관한 이야기 

https://discuss.api.ai/t/how-to-send-parameters-to-api-ai-using-nodejs-sdk/9876/7



다만, v2 알아둘 것은 v2에서 parameters는 result 가 아니라 queryResult. 이다.


Dialogflow v1과 v2 비교 공식 문서를 가면 알 수 있다. [클릭하면 비교 공식문서로]



request.body.result.parameters.color 가 아니라 parameters.color 라고 쓴 이유





여기서 받아주었기 때문에 밑에서 그냥 parameters.color 라고 써도 된다!



추가

v1 버전

action handler 에 똑같이 make_name action 만들어주고 코드를 다음과 같이!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   'make_name': () => {  
    // Use the Actions on Google lib to respond to Google requests; for other requests use JSON
      if (requestSource === googleAssistantRequest) {
        let responseToUser = {
          //googleRichResponse: googleRichResponse, // Optional, uncomment to enable
          //googleOutputContexts: ['weather', 2, { ['city']: 'rome' }], // Optional, uncomment to enable
          speech: 'Alright, your silly name is ' +
      parameters.color + ' ' + parameters.number +
      '! I hope you like it. See you next time' , // spoken response
          text: 'Alright, your silly name is ' +
      parameters.color + ' ' + parameters.number +
      '! I hope you like it. See you next time'// displayed response
        };
        sendGoogleResponse(responseToUser);
      } else {
        let responseToUser = {
          //data: richResponsesV1, // Optional, uncomment to enable
          //outputContexts: [{'name': 'weather', 'lifespan': 2, 'parameters': {'city': 'Rome'}}], // Optional, uncomment to enable
          speech: 'Alright, your silly name is ' +
      parameters.color + ' ' + parameters.number +
      '! I hope you like it. See you next time'// spoken response
          text: 'Alright, your silly name is ' +
      parameters.color + ' ' + parameters.number +
      '! I hope you like it. See you next time' // displayed response
        };
        sendResponse(responseToUser);
      }
    },
cs


끝!

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함