Watson Conversation์—์„œ Condition์„ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ฃผ๊ณ  ๋ฐ›๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ž‘์„ฑํ•  ๋•Œ์—๋Š” SpEL(Spring Expression Language)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. SpEL์€ ๋‹ค์–‘ํ•œ Feature๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค(SpEL Features).

๋นŒํŠธ์ธ ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜(Built-in Global Variables)

Watson Conversation์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋นŒํŠธ์ธ Global ๋ณ€์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

intents[ ] ์ธํ…ํŠธ ๋ชฉ๋ก
entities[ ] ์—”ํ‹ฐํ‹ฐ ๋ชฉ๋ก
input ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ๋‹ด์€ JSON object
output Watson์˜ ์ถœ๋ ฅ๊ฐ’์„ ๋‹ด์€ JSON object
context ์‚ฌ์šฉ์ž์™€ Watson ์‚ฌ์ด์˜ ๋Œ€ํ™” ๋ฌธ๋งฅ์„ ๋‹ด์€ JSON object
conversation_start ์ฒ˜์Œ ๋Œ€ํ™”๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ true๊ฐ€ ๋˜๋Š” Boolean ๊ฐ’์œผ๋กœ ์›ฐ์ปด ๋ฉ”์„ธ์ง€์˜ Condition์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
anything_else ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’์ด ์–ด๋Š ์ธํ…ํŠธ์—๋„ ๋งค์น˜๋˜์ง€ ์•Š์„ ๋•Œ ์ด Condition์„ ์‚ฌ์šฉํ•œ ๋…ธ๋“œ์˜ ์ถœ๋ ฅ๊ฐ’์ด ์‚ฌ์šฉ๋จ

๋Œ€ํ™”์—์„œ ์ถ”์ถœ๋œ Entity ์‚ฌ์šฉํ•˜๊ธฐ

๋Œ€ํ™” ์ค‘ ์ถ”์ถœ๋œ Entity๋ฅผ ํ™œ์šฉํ•˜๋Š” ํ‘œํ˜„์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์‹œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

entities.airport[0].literal == 'Kennedy Airport'
entities.airport[0].value == 'JFK Airport'
< ? entities.city.literal ?>
์งง์€ ๋ฌธ๋ฒ• SpEL ๋ฌธ๋ฒ•
@year entities[‘year’]?.value
@year == 2016 entities[‘year’]?.value == 2016
@year != 2016 entities[‘year’]?.value != 2016
@city == ‘Boston’ entities[‘city’]?.value == ‘Boston’
@city:Boston entities[‘city’]?.contains(‘Boston’)
@city:(New York) entities[‘city’]?.contains(‘New York’)

SpEL์—์„œ ? ๋งˆํฌ๋Š” ๋ณ€์ˆ˜๊ฐ€ null์ธ ๊ฒฝ์šฐ๋ฅผ ์ฒดํฌํ•˜์—ฌ null point exception์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ์ปจ๋””์…˜์„ ์˜ˆ๋กœ ๋“ค๋ฉด,

entities['city']?.contains('Boston')

์ด ์ปจ๋””์…˜์€ ์ ์–ด๋„ ํ•˜๋‚˜์˜ Boston์ด @city ์—”ํ‹ฐํ‹ฐ์—์„œ ๋ฐœ๊ฒฌ๋  ๋•Œ true๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋ž˜์˜ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋ƒˆ๋‹ค๋ฉด

I want to go from Toronto to Boston.

@city:Toronto ์™€ @city:Boston, 2๊ฐœ์˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋ฐœ๊ฒฌ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐ’์€ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ฉ๋‹ˆ๋‹ค.

entities: entities.city[0].value = 'Toronto'
entities.city[1].value = 'Boston'

์ด ์˜ˆ์ œ์—์„œ, ์œ„์˜ ์ปจ๋””์…˜ entities.city.contains(‘Boston’)์€ Boston์ด ์—”ํ‹ฐํ‹ฐ์˜ ๋‘๋ฒˆ์งธ ๊ฐ’์ด๋”๋ผ๋„ true๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ธํ’‹(input) ์‚ฌ์šฉํ•˜๊ธฐ

์‚ฌ์šฉ์ž ์ธํ’‹์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

input.text == 'yes'
input.text.contains( 'yes' )
input.text.matches( '[0-9]+' )

์ธํ…ํŠธ(intent) ์‚ฌ์šฉํ•˜๊ธฐ

์ธํ…ํŠธ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์•„๋ž˜์˜ ์˜ˆ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

intents[0] == 'Help' or intents == 'Help'

์•„๋ž˜์™€ ๊ฐ™์€ ํฌ๋งท๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์งง์€ ๋ฌธ๋ฒ• SpEL ๋ฌธ๋ฒ•
#help intent == ‘help’
! #help intent != ‘help’
NOT #help intent != ‘help’
#help or #i_am_lost (intent == ‘help’ || intent == ‘I_am_lost’)

๋ฌธ๋งฅ(Context) ์ •๋ณด ํ™œ์šฉํ•˜๊ธฐ

์•„์›ƒํ’‹ ๋ฉ”์„ธ์ง€์— ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„์„ ๋„ฃ๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

"output":{"text":"Your name is < ? context.userName ?>"} 
"output":{"text":"Your name is $userName"} 

๋ฌธ๋งฅ(Context)์— ๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ ์œ„ํ•ด ํ•ฉ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

"context":{"toppings": "< ? context.toppings.append( 'onions' ) ?>"}
์งง์€ ๋ฌธ๋ฒ• SpEL ๋ฌธ๋ฒ•
$card_type:VISA context[‘card_type’] == ‘VISA’
$card_type:(MASTER CARD) context[‘card_type’] == ‘MASTER CARD’

ํ•จ์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ

์ปจ๋””์…˜ ๋˜๋Š” Response์— ์•„๋ž˜์™€ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ๋งฅ(Context)์„ ๊ฐ–๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

{
  "context": {
    "toppings_array": ["onion", "olives", "ham"]
  }
}

์ปจ๋””์…˜์— ์•„๋ž˜์™€ ๊ฐ™์ด contains ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{
  "conditions": "$toppings_array.contains('ham')"
}

๋˜๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

{
  "output": {
    "text": "This is the array: < ? $toppings_array.join(';') ?>"
  }
}

JSONArray ํƒ€์ž…์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • JSONArray.size()
  • JSONArray.append(object)
  • JSONArray.remove(integer)
  • JSONArray.removeValue(object)
  • JSONArray.get(integer)
  • JSONArray.getRandomItem()
  • JSONArray.join(string delimiter)
  • JSONArray.contains(object value)
  • JSONArray.set(integer index, object value)

JSONObject ํƒ€์ž…์—๋Š” ์•„๋ž˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  • JSONObject.has(string)
  • JSONObject.remove(string)

String ํƒ€์ž…์€ ์•„๋ž˜์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•˜์‹ญ์‹œ์˜ค.

  • String.length()
  • String.toUpperCase()
  • String.toLowerCase()
  • String.endsWith(string)
  • String.startsWith(string)
  • String.isEmpty()
  • String.trim()
  • String.substring(int beginindex, int endindex)
  • String.append(object)
  • String.matches(String regexp)
  • String.extract(String regexp, Integer groupIndex)
  • String.split(String regexp)

์•„๋ž˜๋Š” ์ˆซ์ž ํƒ€์ž…์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

  • Number.toInt()
  • Number.toLong()
  • Number.toDouble()

์‹œ์Šคํ…œ ์—”ํ‹ฐํ‹ฐ(System Entity) ์‚ฌ์šฉํ•˜๊ธฐ

Watson Conversation์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ ์—”ํ‹ฐํ‹ฐ ์™ธ์—๋„ ์‹œ์Šคํ…œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ ์งœ, ์‹œ๊ฐ„, ์ˆซ์ž, ํ†ตํ™”, Timezone ๋“ฑ์˜ ์‹œ์Šคํ…œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด ๊ธฐ๋Šฅ์„ Enable ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ ์—”ํ‹ฐํ‹ฐ ์‚ฌ์šฉ๋ฒ•์„ ์ฐธ์กฐํ•˜์—ฌ ์ ์ ˆํ•˜๊ฒŒ ํ™œ์šฉํ•˜๋ฉด ์ข€ ๋” ์‰ฝ๊ฒŒ ๋กœ์ง์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž„์กด(Timezone)๊ณผ ๊ด€๋ จ๋œ ์‹œ์Šคํ…œ ์—”ํ‹ฐํ‹ฐ๋„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

@sys-number ์—”ํ‹ฐํ‹ฐ

@sys-number ์—”ํ‹ฐํ‹ฐ๋Š” ์•„๋ž˜ ์ฒ˜๋Ÿผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์†์„ฑ ํƒ€์ž… ๋ฆฌํ„ด ํƒ€์ž… : twenty ๋ฆฌํ„ด ํƒ€์ž… : 1,234.56
@sys-number string 20 1234.56
@sys-number.literal string twenty 1,234.56
@sys-number.numeric_value number 20 1234.56

@sys-date์™€ @sys-time ์—”ํ‹ฐํ‹ฐ

@sys-date๋Š” Friday, today, November 1 ๊ณผ ๊ฐ™์€ ๋‚ ์งœ ๊ฐ’์„ ์ถ”์ถœํ•ด ๋‚ด๋Š” ์—”ํ‹ฐํ‹ฐ ์ž…๋‹ˆ๋‹ค. ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐ’์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’์œผ๋กœ๋ถ€ํ„ฐ ๋‚ ์งœ ๊ฐ’์„ ์ถ”๋ก ํ•˜์—ฌ “yyyy-MM-dd” ํฌ๋งท์˜ string์œผ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ November 1๋งŒ ์ž…๋ ฅํ•˜๋”๋ผ๋„ ์‹œ์Šคํ…œ์€ ํ˜„์žฌ ๋‚ ์งœ๋กœ ์—ฐ๋„๋ฅผ ์ถ”์ธกํ•˜์—ฌ ๊ฐ’์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

@sys-time์€ 2pm, at 4, 15:30 ๊ณผ ๊ฐ™์€ ์‹œ๊ฐ„ ๊ฐ’์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ถ”์ถœ๋œ ๊ฐ’์€ “HH:mm:ss” ํฌ๋งท์˜ string์œผ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

< ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ํ•จ๊ป˜ ์–ธ๊ธ‰ํ•  ๋•Œ>

์ง€๊ธˆ(now) ๋˜๋Š” 2์‹œ๊ฐ„ ๋’ค์—(two hours from now)์™€ ๊ฐ™์€ ๋ง์—์„œ๋Š” @sys-date์™€ @sys-time๊ฐ€ ๋™์‹œ์— ์ถ”์ถœ๋ฉ๋‹ˆ๋‹ค. ์›”์š”์ผ 4์‹œ(Monday at 4pm)์™€ ๊ฐ™์€ ๋ง ๋˜ํ•œ @sys-date์™€ @sys-time์ด ๋™์‹œ์— ์ถ”์ถœ๋ฉ๋‹ˆ๋‹ค. ๋‚ ์งœ์™€ ์‹œ๊ฐ„์ด ์—ฐ์†์ ์œผ๋กœ ์–ธ๊ธ‰๋  ๋•Œ์—๋Š” ์ด์ฒ˜๋Ÿผ ๋‘ ์ •๋ณด๊ฐ€ ํ•˜๋‚˜๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์ถ”์ถœ๋ฉ๋‹ˆ๋‹ค.

< ๋‚ ์งœ์™€ ์‹œ๊ฐ„์˜ ๋ฒ”์œ„๋ฅผ ์–ธ๊ธ‰ํ•  ๋•Œ>

์ฃผ๋ง(the weekend), ๋‹ค์Œ ์ฃผ(next week), ์›”์š”์ผ๋ถ€ํ„ฐ ๊ธˆ์š”์ผ๊นŒ์ง€(From Monday to Friday)์™€ ๊ฐ™์€ ๋‚ ์งœ์˜ ๋ฒ”์ฃผ๊ฐ€ ์–ธ๊ธ‰๋  ๋•Œ์—๋Š” ๋‘ ์Œ์˜ @sys-date ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ถ”์ถœ๋˜์–ด ์‹œ์ž‘๊ณผ ๋์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด์™€ ๋น„์Šทํ•˜๊ฒŒ 2์‹œ์—์„œ 3์‹œ(From 2 to 3)์™€ ๊ฐ™์€ ์‹œ๊ฐ„ ๋ฒ”์œ„๋ฅผ ์–ธ๊ธ‰ํ•˜๋ฉด ๋‘๊ฐœ์˜ @sys-time ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ถ”์ถœ๋ฉ๋‹ˆ๋‹ค.

< ํƒ€์ž„์กด(Timezone)>

ํ˜„์žฌ ์‹œ๊ฐ„๊ณผ ๊ด€๋ จ๋œ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ์–ธ๊ธ‰ํ•  ๋•Œ์—๋Š” ํƒ€์ž„์กด์— ๋”ฐ๋ผ์„œ ๊ฐ’์ด ๊ณ„์‚ฐ๋ฉ๋‹ˆ๋‹ค. ํƒ€์ž„์กด์„ ๋”ฐ๋กœ ์„ ํƒํ•˜์ง€ ์•Š์œผ๋ฉด UTC(GMT) ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ UTC(GMT)์™€ ๋‹ค๋ฅธ ํƒ€์ž„์กด์— ์žˆ๋‹ค๋ฉด ์ปจํ…์ŠคํŠธ(context) ๋ณ€์ˆ˜์ธ $timezone์— ํ•ด๋‹น ์ง€์—ญ์˜ ํƒ€์ž„์กด์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€์ˆ˜๋Š” ๋ชจ๋“  request์— ๋ณด๋‚ด์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค. $timezone ๊ฐ’์˜ ์˜ˆ๋กœ๋Š” America/Los_Angeles, EST, UTC ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€์›๋˜๋Š” ์ „์ฒด ํƒ€์ž„์กด ๋ชฉ๋ก์„ ํ™•์ธํ•˜๊ณ  ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

$timezone ๋ณ€์ˆ˜๊ฐ€ ์ œ๊ณต๋˜๋ฉด @sys-date์™€ @sys-time ๊ฐ’์€ ๋ชจ๋‘ UTC ๋Œ€์‹  ์„ค์ •๋œ timezone์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๊ฐ’์œผ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

< @sys-date์˜ ์‚ฌ์šฉ ์˜ˆ์‹œ>
์†์„ฑ ํƒ€์ž… ๋ฆฌํ„ด ํƒ€์ž… : November 21
@sys-date.literal string November 21
@sys-date string 20xx-11-21 *
@sys-date.location array [0,11]
@sys-date.calendar_type string GREGORIAN
  • ์—ฐ๋„๋ฅผ ํŠน๋ณ„ํžˆ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ ์งœ์˜ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฏธ๋ž˜์˜ ์—ฐ๋„๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.
< @sys-time์˜ ์‚ฌ์šฉ ์˜ˆ์‹œ>
์†์„ฑ ํƒ€์ž… ๋ฆฌํ„ด ํƒ€์ž… : at 6 pm
@sys-time.literal string at 6 pm
@sys-time string 18:00:00
@sys-time.location array [0,7]
@sys-time.calendar_type string GREGORIAN
< @sys-date์™€ @sys-time์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜๋“ค>

@sys-date์™€ @sys-time์œผ๋กœ ์ถ”์ถœ๋œ ๊ฐ’์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋“ค์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • .before(String date or time)
  • .after(String date/time)
  • .sameOrBefore(String date/time)
  • .sameOrAfter(String date/time)
  • .sameMoment(String date/time)
  • .reformatDateTime(String format)
  • now()

์œ„์˜ ํ•จ์ˆ˜๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

@sys-time.before('12:00:00')
@sys-date.before('2016-11-21')

๋…ธ๋“œ์˜ ์ปจ๋””์…˜์— now()ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

{
  "conditions": "now().before('12:00:00')",
  "output": {
    "text": {
      "values": [ "Good morning!" ]
      }
   }
}

* ์ด ๊ธ€์€ ์˜๋ฌธ ๊ฐ€์ด๋“œ๋ฅผ ๋ฒ ์ด์Šค๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (์›๋ฌธ : http://www.ibm.com/watson/developercloud/doc/conversation/expression-language.html)