Clova Extension Kit SDK for Python¶
This is a python library to simplify the use of the Clova Extensions Kit (CEK). If you want to create your own service, you first need to create your own Extension. https://clova-developers.line.me/
Quick start¶
- Create a
cek.clova.Clova
instance.
import os
from cek import Clova
# application_id is used to verify requests.
application_id = os.environ.get("APPLICATION_ID")
# Set debug_mode=True if you are testing your extension. If True, this disables request verification
clova = Clova(application_id=application_id, default_language="ja", debug_mode=False)
- Define request handlers for CEK (on LaunchRequest, IntentRequest, etc).
@clova.handle.launch
def launch_request_handler(clova_request):
return clova.response("こんにちは世界。スキルを起動します")
@clova.handle.default
def default_handler(clova_request):
return clova.response("もう一度お願いします")
- Setup a web API endpoint. Use
cek.clova.Clova.route()
to route requests.
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/app', methods=['POST'])
def my_service():
resp = clova.route(request.data, request.headers)
resp = jsonify(resp)
# make sure we have correct Content-Type that CEK expects
resp.headers['Content-Type'] = 'application/json;charset-UTF-8'
return resp
- Save as
app.py
and run app
FLASK_APP=app.py flask run
For a detailed example, see clova-cek-sdk-python-sample example extension. See also the API documentation to know how to use the SDK.
Core¶
Provides types and helpers to create and work with CEK responses easily.
For a high-level interface upon the cek.core
module, see documentation for cek.clova
module.
Request¶
-
class
cek.core.
Request
(request_dict)¶ Type represents a request from CEK
Parameters: request_dict (dict) – Dictioanry represents a request from CEK
Variables: - request_type (str) – can be LaunchRequest, IntentRequest, etc.
- intent_name (str) – name of intent if exist, otherwise None.
- is_intent (str) – IntentRequest or not.
- user_id (str) – user id.
- application_id (str) – application id.
- access_token (str) – access token.
- session_id (str) – session id.
- session_attributes (dict) – session attributes.
- slots_dict (dict) – slots as dictionary
-
slot_value
(slot_name)¶ Returns slot value or None if missing.
Parameters: slot_name (str) – slot name Returns: slot value if exists, None otherwise. Return type: str Raises: TypeError: if the request is not an IntentRequest - Usage:
>>> req.slot_value('Light') '電気'
-
verify_application_id
(application_id)¶ Verify application id
Raises: RuntimeError – if application id is incorrect.
Response¶
SpeechBuilder¶
-
class
cek.core.
SpeechBuilder
(default_language='ja')¶ Helper class to build speech objects that can be part of CEK response.
Parameters: default_language (str) – Set default language for all messages. Can be ja
,ko
oren
.Raises: ValueError – if unsupported language is specified. - Usage:
All the examples below assume the following helper is defined in advance.
>>> from cek import SpeechBuilder >>> from pprint import pprint >>> speech_builder = SpeechBuilder(default_language="ja")
Building a plain text object:
>>> speech_builder.plain_text("こんにちは") {'type': 'PlainText', 'lang': 'ja', 'value': 'こんにちは'}
-
plain_text
(message, language=None)¶ Build a PlainText object
Parameters: Returns: Dictionary with the format of a SpeechInfo with type PlainText
Return type: Raises: ValueError – if unsupported language is specified.
- Usage:
>>> speech_builder.plain_text("こんにちは") {'type': 'PlainText', 'lang': 'ja', 'value': 'こんにちは'}
-
simple_speech
(speech_value)¶ Build a SimpleSpeech object
Parameters: speech_value (dict) – speech_value can be plain_text or url SpeechInfo Returns: Dictionary in the format of a SimpleSpeech Return type: dict - Usage:
>>> text = builder.plain_text("こんにちは") >>> pprint(speech_builder.simple_speech(text)) {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}}
-
speech_list
(speech_values)¶ Build a SpeechList object
Parameters: speech_values (list) – List which can consist of plain_text SpeechInfo or url SpeechInfo Returns: Dictionary in the format of a SpeechList Return type: dict - Usage:
>>> from pprint import pprint >>> text = speech_builder.plain_text("こんにちは") >>> url = speech_builder.url("https://dummy.mp3") >>> speech_list = speech_builder.speech_list([text, url]) >>> pprint(speech_list) {'type': 'SpeechList', 'values': [{'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}, {'lang': '', 'type': 'URL', 'value': 'https://dummy.mp3'}]}
-
speech_set
(brief, verbose)¶ Build a SpeechSet object
Parameters: Returns: Dictionary in the format of a SpeechSet
Return type:
ResponseBuilder¶
-
class
cek.core.
ResponseBuilder
(default_language='ja')¶ Helper class to build responses for CEK
Parameters: default_language (str) – Set default language for all messages. Can be ja
,ko
oren
.Raises: ValueError – if unsupported language is specified. - Usage:
All the examples below assume the following helper is defined in advance.
>>> from cek import SpeechBuilder, ResponseBuilder >>> from pprint import pprint >>> speech_builder = SpeechBuilder(default_language="ja") >>> response_builder = ResponseBuilder(default_language="ja")
Building a SimpleSpeech response:
>>> resp = response_builder.simple_speech_text("こんにちは") >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
-
add_reprompt
(response, speech)¶ Add a repromt to your response. It is recommended to use a SimpleSpeech to keep the reprompt short
Parameters: - response (dict-like) – Response Dictionary to which the reprompt should be added
- speech (dict) – Speech can be a Dictionary of Simple Speech, SpeechList or SpeechSet
Returns: Response with added Speech reprompt
Return type: dict-like
-
simple_speech
(speech_value, end_session=False)¶ Build a SimpleSpeech response
Parameters: Returns: Response that wraps a Dictionary in the format of a response for a SimpleSpeech
Return type: - Usage:
>>> text = speech_builder.plain_text("こんにちは") >>> resp = response_builder.simple_speech(text) >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
-
simple_speech_text
(message, language=None, end_session=False)¶ Build SimpleSpeech response with plain_text value
Parameters: Returns: Response that wraps a Dictionary in the format of a response for a SimpleSpeech
Return type: Raises: ValueError – if unsupported language is specified.
- Usage:
>>> resp = response_builder.simple_speech_text("こんにちは") >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
-
speech_list
(speech_values, end_session=False)¶ Build a SpeechList response
Parameters: Returns: Response that wraps a Dictionary in the format of a response for a SpeechList
Return type: - Usage:
>>> text = speech_builder.plain_text("こんにちは") >>> url = speech_builder.url("https://dummy.mp3") >>> resp = response_builder.speech_list([text, url]) >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SpeechList', 'values': [{'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}, {'lang': '', 'type': 'URL', 'value': 'https://dummy.mp3'}]}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
-
speech_set
(brief, verbose, end_session=False)¶ Build a SpeechSet response
Parameters: Returns: Response that wraps a Dictionary in the format of a response for a SpeechSet
Return type:
-
speech_url
(message, url, language=None, end_session=False)¶ Build a SpeechList response with a message and an URL
Parameters: Returns: Response that wraps a Dictionary in the format of a response for a SpeechList
Return type: Raises: ValueError – if unsupported language is specified.
- Usage:
>>> resp = response_builder.speech_url("音楽を再生します", "https://dummy.mp3") >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SpeechList', 'values': [{'lang': 'ja', 'type': 'PlainText', 'value': '音楽を再生します'}, {'lang': '', 'type': 'URL', 'value': 'https://dummy.mp3'}]}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
RequestHandler¶
-
class
cek.core.
RequestHandler
(application_id, debug_mode=False)¶ Helper class to handle requests from CEK.
Parameters: - Usage:
All the examples below assume the following helpers are defined in advance.
>>> from cek import RequestHandler, ResponseBuilder >>> clova_handler = RequestHandler(application_id="", debug_mode=True) >>> builder = ResponseBuilder(default_language="ja", debug_mode=False)
Defining handlers can be done by decorators:
>>> @clova_handler.launch ... def launch_request_handler(clova_request): ... return builder.simple_speech_text("こんにちは世界。スキルを起動します")
>>> @clova_handler.default ... def default_handler(clova_request): ... return builder.simple_speech_text("もう一度お願いします")
If you have defined request handlers, then setup a web API endpoint as follows:
>>> rom flask import Flask, request, jsonify >>> app = Flask(__name__) >>> @app.route('/app', methods=['POST']) ... def my_service(): ... resp = clova_handler.route_request(request.data, request.headers) ... resp = jsonify(resp) ... resp.headers['Content-Type'] = 'application/json;charset-UTF-8' ... return resp
-
default
(func)¶ Default handler
Parameters: func – Function - Usage:
>>> @clova_handler.default ... def default_handler(clova_request): ... return builder.simple_speech_text("もう一度お願いします")
-
end
(func)¶ End handler called on SessionEndedRequest.
Parameters: func – Function - Usage:
>>> @clova_handler.end ... def end_handler(clova_request): ... # Session ended, this handler can be used to clean up ... return
-
intent
(intent)¶ Intent handler called on IntentRequest.
Parameters: intent (str) – intent name - Usage:
>>> @clova_handler.intent("Clova.YesIntent") ... def intent_handler(clova_request): ... return builder.simple_speech_text("はい、わかりました。")
-
launch
(func)¶ Launch handler called on LaunchRequest.
Parameters: func – Function - Usage:
>>> @clova_handler.launch ... def launch_request_handler(clova_request): ... return builder.simple_speech_text("こんにちは世界。スキルを起動します")
-
route_request
(request_body, request_header_dict)¶ Route request from CEK.
Parameters: Returns: Returns body for CEK response
Return type: Raises: - cryptography.exceptions.InvalidSignature – (non-debug mode only) if request verification failed.
- RuntimeError – (non-debug mode only) if application id is incorrect.
- Usage:
>>> from flask import Flask, request, Response >>> app = Flask(__name__) >>> @app.route('/app', methods=['POST']) ... def my_service(): ... resp = clova_handler.route_request(request.data, request.headers) ... resp = jsonify(resp) ... resp.headers['Content-Type'] = 'application/json;charset-UTF-8' ... return resp
Clova¶
An abstracted layer on top of the cek.core
module.
URL¶
Message¶
MessageSet¶
Clova¶
-
class
cek.clova.
Clova
(application_id, default_language='ja', debug_mode=False)¶ Clova provides the easiest way to create your extension.
Parameters: Raises: ValueError – if unsupported language is specified.
Variables: handle (RequestHandler) – Helper to handle requests from CEK. Request handlers must be defined using the handler.
- Usage:
Create
Clova
instance:>>> from cek import Clova >>> clova = Clova(application_id='', default_language='jp', debug_mode=True)
Define request handlers using (
Clova.handle
). Response can be created usingClova.response()
.>>> @clova.handle.launch ... def launch_request_handler(clova_request): ... return clova.response("こんにちは世界。スキルを起動します")
>>> @clova.handle.default ... def default_handler(clova_request): ... return clova.response("もう一度お願いします")
Plug into your web application using
Clova.route()
:>>> rom flask import Flask, request, jsonify >>> app = Flask(__name__) >>> @app.route('/app', methods=['POST']) ... def my_service(): ... resp = clova.route(request.data, request.headers) ... resp = jsonify(resp) ... resp.headers['Content-Type'] = 'application/json;charset-UTF-8' ... return resp
See docs for
Clova.route()
andClova.response()
for detailed usages.-
response
(message, reprompt=None, end_session=False)¶ Create a Response that should be sent back to CEK
Parameters: Returns: Response containing passed message
Return type: Raises: ValueError – if unsupported language is specified.
- Usage:
>>> import cek >>> from cek import Clova >>> from pprint import pprint >>> clova = Clova(application_id="", default_language="ja", debug_mode=True)
Simplest case:
>>> resp = clova.response("こんにちは") >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
With explicit language:
>>> resp = clova.response(cek.Message("English", language="en")) >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'en', 'type': 'PlainText', 'value': 'English'}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
URL:
>>> resp = clova.response(cek.URL("https://dummy.mp3")) >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': '', 'type': 'URL', 'value': 'https://dummy.mp3'}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
List:
>>> resp = clova.response(["こんにちは", cek.URL("https://dummy.mp3")]) >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SpeechList', 'values': [{'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}, {'lang': '', 'type': 'URL', 'value': 'https://dummy.mp3'}]}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
With reprompt message:
>>> resp = clova.response("こんにちは", reprompt="聞こえていますか?") >>> pprint(resp) {'response': {'card': {}, 'directives': [], 'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': 'こんにちは'}}, 'reprompt': {'outputSpeech': {'type': 'SimpleSpeech', 'values': {'lang': 'ja', 'type': 'PlainText', 'value': '聞こえていますか?'}}}, 'shouldEndSession': False}, 'sessionAttributes': {}, 'version': '1.0'}
-
route
(body, header)¶ Route request from CEK to handlers
Depending on the request type (intent, launch, etc), the function routes the request to the proper handler defined by the user and returns the response as a dictionary. Request verifiation is done per request before routing.
The method is an alias to
cek.core.RequestHandler.route_request()
.Parameters: Returns: Returns body for CEK response
Return type: Raises: - cryptography.exceptions.InvalidSignature – (non-debug mode only) if request verification failed.
- RuntimeError – (non-debug mode only) if application id is incorrect.
- Usage:
>>> from cek import Clova >>> clova = Clova(application_id="", default_language="ja", debug_mode=True) >>> from flask import Flask, request, jsonify >>> app = Flask(__name__) >>> @app.route('/app', methods=['POST']) ... def my_service(): ... resp = clova.route(request.data, request.headers) ... resp = jsonify(resp) ... resp.headers['Content-Type'] = 'application/json;charset-UTF-8' ... return resp