iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
1

今天要來跟各位一起解析 QnA Maker Bot,以下簡稱 QA Bot。

今天是參考 官方範例程式碼

bots/qna_bot.py

class QnABot(ActivityHandler):
    def __init__(
        self,
        conversation_state: ConversationState,
        user_state: UserState,
        dialog: Dialog,
    ):
        self.conversation_state = conversation_state
        self.user_state = user_state
        self.dialog = dialog

    async def on_turn(self, turn_context: TurnContext):
        await super().on_turn(turn_context)
        await self.conversation_state.save_changes(turn_context)
        await self.user_state.save_changes(turn_context)

    async def on_members_added_activity(
        self, members_added: List[ChannelAccount], turn_context: TurnContext
    ):
        for member in members_added:
            if member.id != turn_context.activity.recipient.id:
                await turn_context.send_activity("Hello and welcome!")

    async def on_message_activity(self, turn_context: TurnContext):
        await DialogHelper.run_dialog(
            self.dialog,
            turn_context,
            self.conversation_state.create_property("DialogState"),
        )

這裡大家不知道有沒有發現一件事情,就是這個範例明明有用到 Dialog,但是卻沒有看到像昨天一樣的 .py 檔。這是因為 Microsoft 專門幫 QnA Maker 寫了一個 dialog.py 檔,放在 SDK 裡了。

qnamaker_dialog.py

qnamaker_dialog.py

    def __init__(
        self,
        knowledgebase_id: str,
        endpoint_key: str,
        hostname: str,
        no_answer: Activity = None,
        threshold: float = DEFAULT_THRESHOLD,
        active_learning_card_title: str = DEFAULT_CARD_TITLE,
        card_no_match_text: str = DEFAULT_CARD_NO_MATCH_TEXT,
        top: int = DEFAULT_TOP_N,
        card_no_match_response: Activity = None,
        strict_filters: [Metadata] = None,
        dialog_id: str = "QnAMakerDialog",
    ):
        """
        Initializes a new instance of the QnAMakerDialog class.

        :param knowledgebase_id: The ID of the QnA Maker knowledge base to query.
        :param endpoint_key: The QnA Maker endpoint key to use to query the knowledge base.
        :param hostname: The QnA Maker host URL for the knowledge base, starting with "https://" and
        ending with "/qnamaker".
        :param no_answer: The activity to send the user when QnA Maker does not find an answer.
        :param threshold: The threshold for answers returned, based on score.
        :param active_learning_card_title: The card title to use when showing active learning options
        to the user, if active learning is enabled.
        :param card_no_match_text: The button text to use with active learning options,
        allowing a user to indicate none of the options are applicable.
        :param top: The maximum number of answers to return from the knowledge base.
        :param card_no_match_response: The activity to send the user if they select the no match option
        on an active learning card.
        :param strict_filters: QnA Maker metadata with which to filter or boost queries to the
        knowledge base; or null to apply none.
        :param dialog_id: The ID of this dialog.
        """
        super().__init__(dialog_id)


        self.knowledgebase_id = knowledgebase_id
        self.endpoint_key = endpoint_key
        self.hostname = hostname
        self.no_answer = no_answer
        self.threshold = threshold
        self.active_learning_card_title = active_learning_card_title
        self.card_no_match_text = card_no_match_text
        self.top = top
        self.card_no_match_response = card_no_match_response
        self.strict_filters = strict_filters


        self.maximum_score_for_low_score_variation = 0.95


        self.add_step(self.__call_generate_answer)
        self.add_step(self.__call_train)
        self.add_step(self.__check_for_multiturn_prompt)
        self.add_step(self.__display_qna_result)

從這個 dialog 的建構函式來看,用的是 waterfall dialog,若要自己客製化步驟,則加在

        ## 若要新增步驟,則是加在這裡,並在底下定義新的函式
        self.add_step(self.__newSTEP)

        self.add_step(self.__call_generate_answer)
        self.add_step(self.__call_train)
        self.add_step(self.__check_for_multiturn_prompt)
        self.add_step(self.__display_qna_result)

config.py

接下來再回到 官方範例程式碼 的 config.py。

import os

class DefaultConfig:
    """ Bot Configuration """

    PORT = 3978
    APP_ID = os.environ.get("MicrosoftAppId", "")
    APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
    QNA_KNOWLEDGEBASE_ID = os.environ.get("QnAKnowledgebaseId", "")
    QNA_ENDPOINT_KEY = os.environ.get("QnAEndpointKey", "")
    QNA_ENDPOINT_HOST = os.environ.get("QnAEndpointHostName", "")

要使用哪一個 QnA Maker 的 Knowledge Base(知識庫) 則是在這邊設定。

app.py

# Create ConversationState and UserState
STORAGE = MemoryStorage()
CONVERSATION_STATE = ConversationState(STORAGE)
USER_STATE = UserState(STORAGE)

# Create the main dialog and bot
DIALOG = QnAMakerDialog(
    CONFIG.QNA_KNOWLEDGEBASE_ID,
    CONFIG.QNA_ENDPOINT_KEY,
    CONFIG.QNA_ENDPOINT_HOST,
)
BOT = QnABot(CONVERSATION_STATE, USER_STATE, DIALOG)

這個範例的 Storage 一樣也是用 In-memory Storage,並且也可以看到 Dialog 是用官方 SDK 的 class 來實作。


若要回顧 QnA Maker 的學理及操作,請參考:

以上是今天嘗試解析 QA Bot 的程式碼,我們明天見。


上一篇
【Day26】建立一個 Bing Search Bot
下一篇
【Day28】建立一個 LUIS Bot
系列文
利用Python開發一個以Azure服務為基底的Chat Bot30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言