Bixby Developer Center

Guides
References

Concept 모델링하기

Concept은 모든 "것"을 표현합니다. 커피, 꽃, 공항과 같은 구체적인 사물이 될 수도 있고, 요일, 항공편, 주문과 같은 추상적인 것을 나타낼 수도 있습니다. 적절히 모델링된 concept은 Bixby의 핵심 요소입니다. Planner가 plan을 실행할 때 concept 모델을 input과 goal로 사용하기 때문입니다. Concept은 프로그래밍 언어에서 말하는 데이터 type과 데이터 구조체에 비유할 수 있습니다.

원시(primitive) concept은 텍스트 또는 숫자와 같은 단순 type을 나타냅니다. 구조체(structure) concept은 명명된 property를 갖는 레코드를 나타내며, 좀 더 복합적입니다. 각 property는 그 자체로 concept입니다. 일반적으로 property는 원시(primitive) concept이지만 구조체(structure) concept도 될 수 있습니다.

또한 concept은 상속 관계를 모델링할 수 있습니다. 예를 들어, 다음 구조체 코드 조각에서 볼 수 있듯 식당은 사업체의 property를 상속합니다.

structure (restaurant.Restaurant) {
description (A business who prepares and serves food to customers)
extends (business.Business)
...

원시(Primitive) Concept

원시(primitive) concept에는 텍스트 또는 숫자와 같은 단순 데이터가 저장됩니다. 원시(primitive) concept에는 다음과 같은 7가지 데이터 type이 있습니다.

  • boolean: true 또는 false value를 가질 수 있는 이진 변수
  • decimal: 양수 또는 음수의 부동 소수점 숫자. 이 type은 소수 자리를 포함할 수 있습니다.
  • enum: 가능한 value(symbol)가 고정된 경우의 열거. 이 type은 가능한 모든 value를 사전에 나열할 수 있는 경우에 사용합니다. 구조체 enum을 함께 참조하십시오.
    Note

    vocab 파일이 없으면 자연어에서 enum이 인식되지 않습니다.

  • integer: 소수 자리가 없는 양의 정수 또는 음의 정수
  • name: Bixby에서 사용 가능한 유니코드 문자열. 문자열이 자연어 input, dialog 또는 vocabulary의 일부인 경우에 사용합니다. 이 type의 예로는 사업체 이름, 메뉴 항목, 영화 제목 등이 있습니다.
  • qualified: 정규식과 매칭되는 name. 문자열의 유효성을 검사하고 Bixby에 문자열을 표시하고자 하나, 가능한 모든 value를 사전에 열거할 수 없는 경우에 이 type을 사용하는 것이 좋습니다. 또한 정규식을 사용하면 Bixby가 유효한 value를 인식하기가 더 쉬워집니다.
  • text: 외부 서비스에 표시하거나 전달할 수는 있으나, vocabulary와 함께 사용할 수 없는 유니코드 문자열. 이 type은 URL, XML 또는 JSON 블록, 대규모 텍스트 블록(예: 영화 또는 식당 리뷰)에 적합합니다.

다음은 몇 가지 예입니다.

qualified (PhoneNumber) {
description (A string representing a phone number.)
regex-pattern ("\\+?1? ?-? ?((\\(\\d\\d\\d\\))|\\d\\d\\d)? ?-? ?\\d\\d\\d ?-? ?\\d\\d\\d\\d")
}
boolean (Confirmation) {
extends (core.Confirmation)
}

View on GitHub

decimal (PlanetSize) {
description (A planet's diameter in miles)
}

View on GitHub

enum (Type) {
description (Type of a shoe.)
symbol (Athletic)
symbol (Boot)
symbol (Casual)
symbol (Dance)
symbol (Formal)
symbol (Sandals)
}

View on GitHub

integer (RollConcept) {
description (The result of a dice roll.)
}

View on GitHub

name (PersonName) {
description ("The person's name. Ex: Jackie Chan")
}

View on GitHub

text (Answer) {
description (The user's answer)
}

View on GitHub

제대로 모델링된 concept은 각 작업에 맞는 적절한 type을 사용합니다. 원시(primitive) concept을 확장하는 경우에는 모든 concept이 동일한 원시 타입(primitive)이어야 합니다. 위의 boolean 예제에서 core.Confirmationboolean 원시 타입(primitive)입니다. Confirmation이 여기에서 상속을 받기 위해서는 이 type이 필요하기 때문입니다.

구조체(Structure) Concept

구조체(structure) concept은 레코드와 유사한 type으로, 다른 프로그래밍 언어의 struct나 키(key)/value 객체와 비슷하다고 할 수 있습니다. 구조체(structure) concept에는 임의 개수의 property가 포함되어 있습니다. 구조체의 각 property는 원시 데이터 type이 아니라 concept이어야 합니다. 아래 property를 참조하십시오.

Bixby가 구조체를 사용하려면 적절한 action 모델과 해당 구조체를 output으로 표시하는 함수가 필요합니다.

예를 들어, 다음 Order 구조체를 살펴보십시오.

structure (Order) {
property (items) {
type (Item)
min (Optional)
max (Many)
}
property (orderNumber) {
type (OrderNumber)
min (Required)
}
property (totalPrice) {
type (Price)
min (Required)
}
property (holdTime) {
type (HoldTime)
min (Required)
}
features {
transaction
}
}

View on GitHub

다음 action 모델은 Order를 output으로 사용합니다.

action (CreateOrder) {
type (BeginTransaction)
collect {
input (initialItems) {
type (InitialItems)
min (Required)
max (One)
default-init {
intent: goal: CreateItems
}
}
}
output (Order)
}

View on GitHub

다음은 이에 해당하는 JavaScript입니다.

var dates = require('dates')
var config = require('config')
//CreateOrder
exports.function = function(initialItems) {
return {
items: initialItems.items,
totalPrice: calculateTotalPrice(initialItems.items),
orderNumber: 23343,
holdTime: dates.ZonedDateTime.now("UTC").plusSeconds(parseInt(config.get("hold_time"))).getMillisFromEpoch()
}
}

function calculateTotalPrice(items) {
var totalPrice = 0
for (var i=0; i<items.length; i++) {
totalPrice += items[i].shirt.price.value * items[i].quantity
}
return {
value: totalPrice,
currencyType: {
prefixSymbol: '$',
currencyCode: 'USD'
}
}
}

View on GitHub

Property

Property는 concept 간의 "has-a" 관계를 정의합니다. 예를 들어, 사업체의 주소 같은 경우에 addressname type의 원시(primitive) concept으로 정의할 수 있고, Business 구조체(structure) concept에는 address를 property로 포함할 수 있습니다.

Property는 이름만 보았을 때도 그 용도를 쉽게 알 수 있어야 합니다. 이렇게 해야 property를 다른 concept 또는 action의 input으로 쉽게 사용할 수 있기 때문입니다. 이러한 이유로 모든 property는 반드시 concept이어야 합니다. 예를 들어 Magnitude property를 구조체의 type (decimal)으로 직접 정의할 수는 없습니다. 이 경우에는 decimal 데이터 type을 사용하여 Magnitude 원시(primitive) concept을 정의해야 합니다.

decimal (Magnitude) {
description (The magnitude of an earthquake)
features {
recognized-range {
min-value(0)
max-value(12)
}
}
}

View on GitHub

그런 다음 구조체의 property에 type (Magnitude)를 사용합니다.

structure (Earthquake) {
description (An earthquake)

property (title) {
type (Title)
min (Optional) max (One)
}
property (dateTime) {
type (EarthquakeDateTime)
min (Optional) max (One)
}
property (location) {
type (EarthquakeLocation)
min (Optional) max (One)
}
property (magnitude) {
type (Magnitude)
min (Optional) max (One)
}
}

View on GitHub

Note

경우에 따라 라이브러리 캡슐을 가져와서 호출하는 방법이 더 간단할 수도 있습니다. 예를 들어 Latitude property가 필요한 경우 viv.geo 라이브러리 캡슐을 가져올 수 있습니다. 이 캡슐에는 사전 정의된 Latitude concept뿐 아니라 상위 레벨의 지리 관련 concept 및 action도 포함되어 있습니다.

개수 제한규칙(Cardinality)

기본적으로 각 property는 개수 제한규칙(cardinality)에서 optional이자 single로 구분됩니다. 다시 말해, 선택적으로 하나의 value를 가질 수 있습니다. 옵셔널리티는 min 키워드로 설정되고, 개수 제한규칙(cardinality)은 max로 설정됩니다.

min (Optional)max (One)을 사용하여 명시적으로 기본값을 지정할 수 있습니다. property에 개수 제한 없이 value를 사용할 수 있도록 하려면 max (Many)를 지정하고, 적어도 하나의 value를 반드시 사용하도록 하려면 min (Required)를 지정합니다. property에 둘 이상의 value를 사용할 수 있는 경우라면 모든 value가 해당 property의 선언된 type이어야 합니다.

다음 예는 여러 property를 갖는 Hotel 구조체를 보여줍니다.

structure (Hotel) {
property (name) {
type (HotelName)
min (Required) max (One)
}
property (rating) {
type (HotelRating)
min (Required) max (One)
}
property (lowRate) {
type (HotelLowRate)
min (Required) max (One)
}
property (location) {
type (geo.GeoPoint)
min (Optional) max (One)
}
property (reviewCount) {
type (HotelReviewCount)
min (Optional) max (One)
}
property (images) {
type (core.BaseImage)
min (Optional) max (Many)
}
property (amenities) {
type (HotelAmenity)
min (Optional) max (Many)
}
}

View on GitHub

rating property는 하나의 HotelRating value를 가져야 합니다. reviewCount property는 optional이지만, 이 property가 있는 경우에는 HotelReviewCount type이어야 하며 최대 하나의 value만 가질 수 있습니다. 반면, images property와 amenities property는 마찬가지로 optional이지만 여러 개의 value를 가질 수 있습니다.

한 property에는 대개 고유한 value만 저장됩니다. 캡슐에서 max (Many) 노드에 이미 있는 value를 다시 한 번 추가할 경우 추가된 value는 자동으로 병합됩니다. departments property에 ["Hardware", "Toys", "Home Goods"] value가 있다고 할 때, "Kitchen" value는 그대로 추가할 수 있지만 "Toys" value를 추가하는 경우에는 기존의 "Toys" value와 자동으로 병합되고 departments property 내의 모든 value가 고유하게 유지됩니다. 이 동작과 이 동작을 오버라이딩하는 방법에 대한 자세한 내용은 병합 및 Equivalence를 참조하십시오.

Property 표시

경우에 따라 concept 내 property를 planner에 표시하는 것이 좋을 때도 있고 표시하지 않는 것이 좋을 때도 있습니다.

GeoPoint 구조체를 정의하는 경우를 예로 들어 보겠습니다. 이 구조체에는 latitude property와 longitude property가 포함되어 있는데, 이 경우에는 이 구조체의 나머지 부분을 별개로 표시하지 않는 것이 좋습니다. 반면, timeZone property는 visibility(Public)을 사용하여 선언하는 것이 더 좋습니다. 이렇게 하면 일부 실행 plan에 time.TimeZoneId input을 받는 action이 포함되어 있고 시스템에 이미 GeoPoint input이 있는 경우에 도움이 됩니다.

structure (GeoPoint) {
description (A geographic point.)
property (latitude) {
type (Latitude)
min (Required)
}
property (longitude) {
type (Longitude)
min (Required)
}

property (timeZone) {
type (time.TimeZoneId)
visibility (Public)
min (Optional) max (One)
}
}

다음 예는 "get the timezone in Seoul, South Korea"라는 발화의 실행 그래프입니다. NamedPointGeoPoint type의 point property가 포함된 것을 볼 수 있습니다.

timezone graph

마찬가지로, 주식 조회 feature의 경우 증권 거래소(stockExchange)와 주식 종목 코드(StockSymbol) 같이 주로 사용되는 특정 property는 전체 plan에서 계속 사용할 수 있어야 합니다.

structure (ExchangeListing) {
description (Listings on various exchanges)
property (stockExchange) {
type (Exchange)
min (Required) max (One)
visibility (Public)
}
property (companyName) {
type (CompanyName)
min (Required) max (One)
visibility (Public)
}
property (stockSymbol) {
type (StockSymbol)
min (Required) max (One)
visibility (Public)
}
property (ipoYear) {
type (IpoYear)
}
property (companyUrl) {
type (entity.EntityUrl)
}
}

다음은 이것이 어떻게 사용되는지를 보여주는 실행 그래프입니다.

timezone graph

Property가 Default visibility로 설정되면 후속 action은 부모 구조체와 별개로 property를 볼 수 없습니다. 그러나 planner는 최종 goal을 볼 수 있습니다. 라우트(route) 또는 sort value도 마찬가지입니다. 예를 들어 Weather 구조체에 Default visibility를 갖는 DayHighTemperature property가 있을 때 사용자가 "What was the high temperature today?"라고 물을 경우 이것이 plan의 최종 goal이 되어 plan에서 DayHighTemperature property에 직접 액세스할 수 있게 됩니다.

temperature graph

이러한 액세스를 방지하려면 visibility (Private)을 설정하여 이 property를 plan의 어디에서도 사용하지 못하도록 하면 됩니다. 사용자가 사용해서는 안 되고 내부적으로만 사용되는 property를 Private으로 설정해야 합니다.

구조체(Structure) Enum

구조체 enum은 원시(primitive) concept에 사용되는 enum 데이터 type에 상응하는 구조체입니다. 원시 타입(primitive) enum과 구조체 enum 모두 미리 정의된 상수 목록에서 선택한 value를 갖습니다. 그러나 구조체 enum의 상수는 구조체에 포함된 모든 property를 한 번에 설정하며 모든 property를 하나의 열거 목록으로 작성합니다.

다음 예는 구조체 enum의 구문입니다.

structure-enum (CurrencyType) {
property (currencyCode) {
type (CurrencyCode)
}
property (prefixSymbol) {
type (PrefixSymbol)
}
constant: CurrencyType {
prefixSymbol: ($)
currencyCode: (USD)
}
constant: CurrencyType {
prefixSymbol: ()
currencyCode: (EUR)
}
// ... additional currency types ...
}

이 구조체 enum은 prefixSymbolcurrencyCode라는 두 property를 포함하고 있으며 둘을 한데 묶어서 설정합니다.

  • prefixSymbol: $, currencyCode: USD
  • prefixSymbol: €, currencyCode: EUR

보시는 것처럼 이 CurrencyType 구조체 enum은 다른 통화가 필요하고 적절한 통화를 사용해야 하는 모든 캡슐에서 중요합니다.

Concept 간 관계

새 concept을 생성하기 전에 기존 concept을 재사용하거나 확장할 수 있는지 확인해보세요. 이 방법은 시간을 절약하고 기존의 training을 활용할 수 있어 매우 유용할 수 있습니다.

기존 concept을 새 concept의 property로 재사용하는 방법은 이미 살펴보았습니다. 물론 이 방법도 유용하지만, concept 간 관계를 정의하는 방법도 있습니다.

확장

새 자식 concept을 사용하여 부모 concept을 확장(extend)할 수 있습니다. 부모 concept이 property를 가진 구조체일 경우, 자식 concept 또한 해당 property를 상속합니다. 그리고 이러한 자식 concept에 고유한 새 property를 정의할 수 있습니다. 이것은 많은 프로그래밍 언어에서 사용되는 상속(inheritance)과 비슷하게 "is-a" 관계 즉, 부모-자식 또는 하위 집합 관계를 나타냅니다. 원시(primitive) concept과 구조체(structure) concept을 모두 확장할 수 있고, 여러 concept을 동시에 확장할 수도 있습니다.

예를 들어 식당은 일종의 사업체로, 다른 사업체와 마찬가지로 전화번호가 있습니다. 또한 여기에는 메뉴도 있을 수 있습니다. 모든 식당은 사업체이지만 모든 사업체가 식당인 것은 아닙니다. 식당은 일부 사업체에는 없는 특성을 갖습니다. 따라서 모든 식당을 사업체로 간주할 수 있지만 모든 사업체를 식당으로 간주할 수는 없습니다.

다음은 몇 가지 다른 예를 보여줍니다.

// A DeliveryRestaurant is both a Restaurant and a
// Vendor (that has a catalog you can buy from, e.g. a Menu)
structure (DeliveryRestaurant) {
extends (viv.restaurant.Restaurant)
extends (viv.order.Vendor)
}
// A Country is a special type of AdministrativeDivision
structure (CountryDivision) {
extends (AdministrativeDivision)
property (countryCode2) {
type (ISOCountryCode2)
min (Optional)
max (One)
}
property (countryCode3) {
type (ISOCountryCode3)
min (Optional)
max (One)
}
}
structure (ThisPlanet) {
role-of (Planet)
//extends will allow projections as goals description
extends (Planet)
}

View on GitHub

구조체(structure) concept을 확장하는 경우 부모 property를 오버라이딩(override)하도록 선택할 수 있습니다. 이를 통해 특정 value를 바인딩할 수 있습니다. 이 예의 Restaurantbusiness.Business에서 BusinessCategory를 상속하지만 그 value는 항상 "Restaurant"입니다.

structure (Restaurant) {
description (A business who prepares and serves food to customers)
extends (business.Business)
property (name) {
override type (RestaurantName)
}
property (category) {
override bind (Restaurant)
}
property (restaurantStyle) {
type (RestaurantStyle)
max (Many)
}
// ... more properties ...
}

Property type을 보다 구체적인 type으로 오버라이딩할 수도 있습니다. 마지막 예에서 Restaurantname property는 RestaurantName으로 지정되어 있습니다. 이 property는 부모 concept에 사용되는 BusinessName보다 더 구체적입니다. 이것은 RestaurantNameBusinessName을 확장하는 경우에만 동작합니다.

property를 오버라이딩할 때 최소 개수 제한규칙(cardinality)도 변경할 수 있습니다. 단, Optional에서 Required로만 변경 가능합니다.

역할 할당

다른 concept의 역할(role-of)을 concept에 할당하면 동작이 컨텍스트에 따라서만 변경되도록 할 수 있습니다. 그러한 concept의 컨텍스트화로는 새 property를 추가할 수 없습니다. role-of concept에 새 property를 추가하려면 원래 concept을 확장(extend)시켜야 합니다. 여기서 이 concept과 부모 간의 유일한 차이는 컨텍스트입니다.

예를 들어 출발 공항과 도착 공항이 동일할 수 있습니다. DepartureAirportArrivalAirport를 받는 FindFlight action을 예로 들어보겠습니다. 이러한 type이 extension인 경우, plan의 업스트림에 있는 모든 action은 필요한 다운스트림 type을 알고 있어야 하며 subtype을 인스턴스화해야 합니다. 그런데 역할 할당(role assignment)을 사용하면 plan의 업스트림에서 인스턴스화되는 air.Airport를 필요에 따라 특정 역할로 변환할 수 있습니다. 이 방법은 여정에 따라 어떤 공항도 출발 공항이나 도착 공항으로 사용할 수 있어야 하는 여행 앱에서 유용할 수 있습니다.

structure (DepartureAirport) {
role-of (Airport)
}

다음은 이러한 항공편 예약의 실행 그래프입니다.

roles graph

DepartureAirportArrivalAirport는 처음에 Airport로 시작한 후 새 role이 할당된 것을 볼 수 있습니다.

Concept Feature

Concept에 concept features를 플래깅하면 Bixby 플랫폼이 해당 concept을 특별한 방식으로 처리할 수 있습니다. 이러한 특별한 처리 방식은 매우 다양한데, concept을 사용자 프로필과 함께 저장되는 것으로 표시할 수도 있고 value를 전혀 저장하지 않을 수도 있습니다. 이처럼 concept feature를 사용하면 사용자 선호 설정, 개인정보 보호, 보안 등을 관리할 수 있습니다.

  • profile-stored: concept value를 사용자 프로필에 연결하여 저장하고 필요에 따라 가져옵니다.

  • transient: concept value를 저장하지 않고 실행 컨텍스트 전반에서 유지하지도 않습니다.

  • transaction: concept을 transactioncommit action의 input에 사용 가능한 "트랜잭션 드래프트(transaction draft)"로 취급합니다.

  • activity: 커밋 type action을 완료한 결과인 "트랜잭션 레코드"를 나타내며, activity action의 input으로도 사용할 수 있습니다.

  • recognized-range: decimalinteger concept과 함께 사용되어 하한값(min-value) 및 상한값(max-value)으로 사용 가능한 value 범위를 설정합니다.

transactionactivity 기능은 트랜잭션 기능이므로 concept을 트랜잭션 기능으로 표시한 후에는 해당 상태를 관련 지원 파일(transaction의 경우 *.transaction.bxb, activity의 경우 *.activity.bxb)에 정의해야 합니다. 자세한 내용은 트랜잭션 워크플로우에서 확인할 수 있습니다.

Profile-Stored Concept

경우에 따라 사용자가 concept value를 재사용하길 원할 수 있습니다. 예를 들어, 사용자의 이름, 청구지 주소, 선호하는 항공 좌석 설정 등이 있을 수 있습니다. 이러한 concept을 profile-stored로 표시하면 사용자가 원할 경우 해당 value를 저장하여 재사용할 수 있습니다.

structure (FlightPreferences) {
description (Used to store user flight preferences.)
features {
profile-stored { max (Many) }
}
property (seat) {
type (AirplaneSeatType)
}
property (carrier) {
type (CarrierCode)
}
}

이러한 value를 저장하는 것은 optional이며 Bixby는 사용자의 승인을 요청하는 프롬프트를 표시합니다.

ProfileStoredUnique concept

특정 concept value는 싱글톤으로 저장해야 할 수 있습니다. 즉, 해당 concept의 value가 한 번에 하나만 있어야 합니다. 예를 들어 항공편을 예약하는 경우 각 항공권에는 오직 하나의 탑승객 이름이 있어야 합니다. 이러한 제한을 적용하려면 해당 concept을 ProfileStoredUnique로 표시합니다.

Transient concept

Bixby가 concept value를 저장하거나 재사용하지 않도록 하려면 concept을 Transient로 표시합니다. Transient concept은 컨버세이션(conversation)의 과거 컨텍스트에서 재사용되지 않습니다. 예를 들어, 시스템 concept인 time.Tensegeo.CurrentLocation은 Transient concept입니다.