diff --git a/samples/snippets/answer_record_management.py b/samples/snippets/answer_record_management.py new file mode 100644 index 000000000..dd5690dd6 --- /dev/null +++ b/samples/snippets/answer_record_management.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Dialogflow API Python sample showing how to manage AnswerRecord. +""" + +from google.cloud import dialogflow_v2beta1 as dialogflow + + +# [START dialogflow_update_answer_record] +def update_answer_record(project_id, answer_record_id, is_clicked): + """Update the answer record. + + Args: + project_id: The GCP project linked with the conversation profile. + answer_record_id: The answer record id returned along with the + suggestion. + is_clicked: whether the answer record is clicked.""" + + client = dialogflow.AnswerRecordsClient() + answer_record_path = client.answer_record_path(project_id, + answer_record_id) + + response = client.update_answer_record( + answer_record={ + 'name': answer_record_path, + 'answer_feedback': { + 'clicked': is_clicked + } + }, + update_mask={'paths': ['answer_feedback']}) + print('AnswerRecord Name: {}'.format(response.name)) + print('Clicked: {}'.format(response.answer_feedback.clicked)) + return response + + +# [END dialogflow_update_answer_record] diff --git a/samples/snippets/answer_record_management_test.py b/samples/snippets/answer_record_management_test.py new file mode 100644 index 000000000..b72b479e7 --- /dev/null +++ b/samples/snippets/answer_record_management_test.py @@ -0,0 +1,97 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import answer_record_management +import conversation_management +import conversation_profile_management +import participant_management + +PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT') +SMART_REPLY_MODEL = os.getenv('SMART_REPLY_MODEL') +SMART_REPLY_ALLOWLIST = os.getenv('SMART_REPLY_ALLOWLIST') +CONVERSATION_PROFILE_DISPLAY_NAME = 'sample code profile for smart reply' + + +def test_smart_reply(capsys): + """Test smart reply feature. + """ + + # Create conversation profile. + conversation_profile_management.create_conversation_profile_smart_reply( + project_id=PROJECT_ID, + display_name=CONVERSATION_PROFILE_DISPLAY_NAME, + smart_reply_allowlist_name=SMART_REPLY_ALLOWLIST, + smart_reply_model_name=SMART_REPLY_MODEL) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format(CONVERSATION_PROFILE_DISPLAY_NAME) in out + conversation_profile_id = out.split('conversationProfiles/')[1].rstrip() + + # Create conversation. + conversation_management.create_conversation( + project_id=PROJECT_ID, conversation_profile_id=conversation_profile_id) + + out, _ = capsys.readouterr() + conversation_id = out.split('conversations/')[1].rstrip() + + # Create end user participant. + participant_management.create_participant(project_id=PROJECT_ID, + conversation_id=conversation_id, + role='END_USER') + out, _ = capsys.readouterr() + end_user_id = out.split('participants/')[1].rstrip() + + # Create human agent participant. + participant_management.create_participant(project_id=PROJECT_ID, + conversation_id=conversation_id, + role='HUMAN_AGENT') + out, _ = capsys.readouterr() + human_agent_id = out.split('participants/')[1].rstrip() + + # AnalyzeContent + participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=human_agent_id, + text='Hi, how are you?') + out, _ = capsys.readouterr() + assert 'What would you like to know?' in out + + response = participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=end_user_id, + text='I am doing well, just want to check') + out, _ = capsys.readouterr() + assert 'Sounds good.' in out + # Update AnswerRecord. + answer_record_id = response.human_agent_suggestion_results[ + 0].suggest_smart_replies_response.smart_reply_answers[ + 0].answer_record.split('answerRecords/')[1].rstrip() + answer_record_management.update_answer_record( + project_id=PROJECT_ID, + answer_record_id=answer_record_id, + is_clicked=True) + out, _ = capsys.readouterr() + assert 'Clicked: True' in out + + # Complete conversation. + conversation_management.complete_conversation( + project_id=PROJECT_ID, conversation_id=conversation_id) + + # Delete conversation profile. + conversation_profile_management.delete_conversation_profile( + project_id=PROJECT_ID, conversation_profile_id=conversation_profile_id) diff --git a/samples/snippets/conversation_management.py b/samples/snippets/conversation_management.py new file mode 100644 index 000000000..e6c734929 --- /dev/null +++ b/samples/snippets/conversation_management.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Dialogflow API Python sample showing how to manage Conversations. +""" + +from google.cloud import dialogflow_v2beta1 as dialogflow + + +# [START dialogflow_create_conversation] +def create_conversation(project_id, conversation_profile_id): + """Creates a conversation with given values + + Args: + project_id: The GCP project linked with the conversation. + conversation_profile_id: The conversation profile id used to create + conversation.""" + + client = dialogflow.ConversationsClient() + conversation_profile_client = dialogflow.ConversationProfilesClient() + project_path = client.common_project_path(project_id) + conversation_profile_path = ( + conversation_profile_client.conversation_profile_path( + project_id, conversation_profile_id)) + conversation = {'conversation_profile': conversation_profile_path} + response = client.create_conversation(parent=project_path, + conversation=conversation) + + print('Life Cycle State: {}'.format(response.lifecycle_state)) + print('Conversation Profile Name: {}'.format( + response.conversation_profile)) + print('Name: {}'.format(response.name)) + return response + + +# [END dialogflow_create_conversation] + + +# [START dialogflow_get_conversation] +def get_conversation(project_id, conversation_id): + """Gets a specific conversation profile. + + Args: + project_id: The GCP project linked with the conversation. + conversation_id: Id of the conversation.""" + + client = dialogflow.ConversationsClient() + conversation_path = client.conversation_path(project_id, conversation_id) + + response = client.get_conversation(name=conversation_path) + + print('Life Cycle State: {}'.format(response.lifecycle_state)) + print('Conversation Profile Name: {}'.format( + response.conversation_profile)) + print('Name: {}'.format(response.name)) + return response + + +# [END dialogflow_get_conversation] + + +# [START dialogflow_complete_conversation] +def complete_conversation(project_id, conversation_id): + """Completes the specified conversation. Finished conversations are purged from the database after 30 days. + + Args: + project_id: The GCP project linked with the conversation. + conversation_id: Id of the conversation.""" + + client = dialogflow.ConversationsClient() + conversation_path = client.conversation_path(project_id, conversation_id) + conversation = client.complete_conversation(name=conversation_path) + print('Completed Conversation.') + print('Life Cycle State: {}'.format(conversation.lifecycle_state)) + print('Conversation Profile Name: {}'.format( + conversation.conversation_profile)) + print('Name: {}'.format(conversation.name)) + return conversation + + +# [END dialogflow_complete_conversation] diff --git a/samples/snippets/conversation_profile_management.py b/samples/snippets/conversation_profile_management.py new file mode 100644 index 000000000..22ae1d384 --- /dev/null +++ b/samples/snippets/conversation_profile_management.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +"""Dialogflow API Python sample showing how to manage Conversation Profiles. +""" + +from google.cloud import dialogflow_v2beta1 as dialogflow + + +# [START dialogflow_list_conversation_profiles] +def list_conversation_profiles(project_id): + """Lists the conversation profiles belonging to a project. + + Args: project_id: The GCP project linked with the conversation profile.""" + + client = dialogflow.ConversationProfilesClient() + project_path = client.common_project_path(project_id) + response = client.list_conversation_profiles(parent=project_path) + for conversation_profile in response: + print('Display Name: {}'.format(conversation_profile.display_name)) + print('Name: {}'.format(conversation_profile.name)) + return response + + +# [END dialogflow_list_conversation_profiles] + + +# [START dialogflow_create_conversation_profile_article_faq] +def create_conversation_profile_article_faq( + project_id, + display_name, + article_suggestion_knowledge_base_id=None, + faq_knowledge_base_id=None): + """Creates a conversation profile with given values + + Args: project_id: The GCP project linked with the conversation profile. + display_name: The display name for the conversation profile to be + created. + article_suggestion_knowledge_base_id: knowledge base id for article + suggestion. + faq_knowledge_base_id: knowledge base id for faq.""" + + client = dialogflow.ConversationProfilesClient() + project_path = client.common_project_path(project_id) + + conversation_profile = { + 'display_name': display_name, + 'human_agent_assistant_config': { + 'human_agent_suggestion_config': { + 'feature_configs': [] + } + }, + 'language_code': 'en-US' + } + + if article_suggestion_knowledge_base_id is not None: + as_kb_path = dialogflow.KnowledgeBasesClient.knowledge_base_path( + project_id, article_suggestion_knowledge_base_id) + feature_config = { + 'suggestion_feature': { + 'type_': 'ARTICLE_SUGGESTION' + }, + 'suggestion_trigger_settings': { + 'no_small_talk': True, + 'only_end_user': True, + }, + 'query_config': { + 'knowledge_base_query_source': { + 'knowledge_bases': [as_kb_path] + }, + 'max_results': 3 + }, + } + conversation_profile['human_agent_assistant_config'][ + 'human_agent_suggestion_config']['feature_configs'].append( + feature_config) + if faq_knowledge_base_id is not None: + faq_kb_path = dialogflow.KnowledgeBasesClient.knowledge_base_path( + project_id, faq_knowledge_base_id) + feature_config = { + 'suggestion_feature': { + 'type_': 'FAQ' + }, + 'suggestion_trigger_settings': { + 'no_small_talk': True, + 'only_end_user': True, + }, + 'query_config': { + 'knowledge_base_query_source': { + 'knowledge_bases': [faq_kb_path] + }, + 'max_results': 3 + }, + } + conversation_profile['human_agent_assistant_config'][ + 'human_agent_suggestion_config']['feature_configs'].append( + feature_config) + + response = client.create_conversation_profile( + parent=project_path, conversation_profile=conversation_profile) + + print('Conversation Profile created:') + print('Display Name: {}'.format(response.display_name)) + # Put Name is the last to make it easier to retrieve. + print('Name: {}'.format(response.name)) + return response + + +# [END dialogflow_create_conversation_profile_article_faq] + + +# [START dialogflow_create_conversation_profile_smart_reply] +def create_conversation_profile_smart_reply(project_id, display_name, + smart_reply_allowlist_name, + smart_reply_model_name): + """Creates a conversation profile with given values for smart reply + + Args: project_id: The GCP project linked with the conversation profile. + display_name: The display name for the conversation profile to be + created. + smart_reply_allowlist_name: document name for smart reply allowlist. + smart_reply_model_name: conversation model name for smart reply.""" + + client = dialogflow.ConversationProfilesClient() + project_path = client.common_project_path(project_id) + + conversation_profile = { + 'display_name': display_name, + 'human_agent_assistant_config': { + 'human_agent_suggestion_config': { + 'feature_configs': [] + } + }, + 'language_code': 'en-US' + } + feature_config = { + 'suggestion_feature': { + 'type_': 'SMART_REPLY' + }, + 'suggestion_trigger_settings': { + 'no_small_talk': True, + 'only_end_user': True, + }, + 'query_config': { + 'document_query_source': { + 'documents': [smart_reply_allowlist_name] + }, + 'max_results': 3 + }, + 'conversation_model_config': { + 'model': smart_reply_model_name + } + } + conversation_profile['human_agent_assistant_config'][ + 'human_agent_suggestion_config']['feature_configs'].append( + feature_config) + + response = client.create_conversation_profile( + parent=project_path, conversation_profile=conversation_profile) + + print('Conversation Profile created:') + print('Display Name: {}'.format(response.display_name)) + # Put Name is the last to make it easier to retrieve. + print('Name: {}'.format(response.name)) + return response + + +# [END dialogflow_create_conversation_profile_smart_reply] + + +# [START dialogflow_get_conversation_profile] +def get_conversation_profile(project_id, conversation_profile_id): + """Gets a specific conversation profile. + + Args: project_id: The GCP project linked with the conversation profile. + conversation_profile_id: Id of the conversation profile.""" + + client = dialogflow.ConversationProfilesClient() + conversation_profile_path = client.conversation_profile_path( + project_id, conversation_profile_id) + + response = client.get_conversation_profile(name=conversation_profile_path) + + print('Got conversation profile:') + print('Display Name: {}'.format(response.display_name)) + print('Name: {}'.format(response.name)) + return response + + +# [END dialogflow_get_conversation_profile] + + +# [START dialogflow_delete_conversation_profile] +def delete_conversation_profile(project_id, conversation_profile_id): + """Deletes a specific conversation profile. + + Args: project_id: The GCP project linked with the conversation profile. + conversation_profile_id: Id of the conversation profile.""" + + client = dialogflow.ConversationProfilesClient() + conversation_profile_path = client.conversation_profile_path( + project_id, conversation_profile_id) + + client.delete_conversation_profile(name=conversation_profile_path) + + print('Conversation Profile deleted.') + + +# [END dialogflow_delete_conversation_profile] diff --git a/samples/snippets/conversation_profile_management_test.py b/samples/snippets/conversation_profile_management_test.py new file mode 100644 index 000000000..0347a8b34 --- /dev/null +++ b/samples/snippets/conversation_profile_management_test.py @@ -0,0 +1,67 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import + +import os + +import conversation_profile_management + +PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT') + +CONVERSATION_PROFILE_DISPLAY_NAME = 'fake_conversation_profile_name' + + +def test_create_conversation_profile(capsys): + # Check the conversation profile does not yet exists. + conversation_profile_management.list_conversation_profiles(PROJECT_ID) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format( + CONVERSATION_PROFILE_DISPLAY_NAME) not in out + + # Create a conversation profile. + conversation_profile_management.create_conversation_profile_article_faq( + project_id=PROJECT_ID, display_name=CONVERSATION_PROFILE_DISPLAY_NAME, + article_suggestion_knowledge_base_id='abc') + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format( + CONVERSATION_PROFILE_DISPLAY_NAME) in out + + conversation_profile_id = out.split('conversationProfiles/')[1].rstrip() + + # List conversation profiles. + conversation_profile_management.list_conversation_profiles(PROJECT_ID) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format( + CONVERSATION_PROFILE_DISPLAY_NAME) in out + + # Get the conversation profile. + conversation_profile_management.get_conversation_profile( + PROJECT_ID, conversation_profile_id) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format(CONVERSATION_PROFILE_DISPLAY_NAME) in out + + # Delete the conversation profile. + conversation_profile_management.delete_conversation_profile( + PROJECT_ID, conversation_profile_id) + + # Verify the converstion profile is deleted. + conversation_profile_management.list_conversation_profiles(PROJECT_ID) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format( + CONVERSATION_PROFILE_DISPLAY_NAME) not in out diff --git a/samples/snippets/create_document_test.py b/samples/snippets/create_document_test.py index 337976c45..b65e577aa 100644 --- a/samples/snippets/create_document_test.py +++ b/samples/snippets/create_document_test.py @@ -17,7 +17,8 @@ import os import uuid -from google.cloud import dialogflow_v2beta1 +from google.cloud import dialogflow_v2beta1 as dialogflow + import pytest import document_management @@ -31,23 +32,21 @@ @pytest.fixture(scope="function", autouse=True) def setup_teardown(): # Create a knowledge base to use in document management - client = dialogflow_v2beta1.KnowledgeBasesClient() + client = dialogflow.KnowledgeBasesClient() project_path = client.common_project_path(PROJECT_ID) - knowledge_base = dialogflow_v2beta1.KnowledgeBase(display_name=KNOWLEDGE_BASE_NAME) - response = client.create_knowledge_base( - parent=project_path, knowledge_base=knowledge_base - ) - pytest.KNOWLEDGE_BASE_ID = response.name.split("/knowledgeBases/")[1].split("\n")[0] + knowledge_base = dialogflow.KnowledgeBase(display_name=KNOWLEDGE_BASE_NAME) + response = client.create_knowledge_base(parent=project_path, + knowledge_base=knowledge_base) + pytest.KNOWLEDGE_BASE_ID = response.name.split( + "/knowledgeBases/")[1].split("\n")[0] yield # Delete the created knowledge base - knowledge_base_path = client.knowledge_base_path( - PROJECT_ID, pytest.KNOWLEDGE_BASE_ID - ) - request = dialogflow_v2beta1.DeleteKnowledgeBaseRequest( - name=knowledge_base_path, force=True - ) + knowledge_base_path = client.knowledge_base_path(PROJECT_ID, + pytest.KNOWLEDGE_BASE_ID) + request = dialogflow.DeleteKnowledgeBaseRequest(name=knowledge_base_path, + force=True) client.delete_knowledge_base(request=request) diff --git a/samples/snippets/document_management.py b/samples/snippets/document_management.py index 4cbd8a346..b08ddf752 100644 --- a/samples/snippets/document_management.py +++ b/samples/snippets/document_management.py @@ -20,21 +20,54 @@ python document_management.py -h python document_management.py --project-id PROJECT_ID \ --knowledge-base-id knowledge_base_id \ + list + python document_management.py --project-id PROJECT_ID \ + --knowledge-base-id knowledge_base_id \ create --display-name DISPLAY_NAME --mime-type MIME_TYPE \ --knowledge-type KNOWLEDGE_TYPE --content-uri CONTENT_URI python document_management.py --project-id PROJECT_ID \ --knowledge-base-id knowledge_base_id \ + get --document-id DOCUMENT_ID + python document_management.py --project-id PROJECT_ID \ + --knowledge-base-id knowledge_base_id \ + delete --document-id DOCUMENT_ID """ import argparse -KNOWLEDGE_TYPES = ["KNOWLEDGE_TYPE_UNSPECIFIED", "FAQ", "EXTRACTIVE_QA"] + +KNOWLEDGE_TYPES = ['KNOWLEDGE_TYPE_UNSPECIFIED', 'FAQ', 'EXTRACTIVE_QA', 'ARTICLE_SUGGESTION'] + + +# [START dialogflow_list_document] +def list_documents(project_id, knowledge_base_id): + """Lists the Documents belonging to a Knowledge base. + + Args: + project_id: The GCP project linked with the agent. + knowledge_base_id: Id of the Knowledge base.""" + from google.cloud import dialogflow_v2beta1 as dialogflow + client = dialogflow.DocumentsClient() + knowledge_base_path = dialogflow.KnowledgeBasesClient.knowledge_base_path( + project_id, knowledge_base_id) + + print('Documents for Knowledge Id: {}'.format(knowledge_base_id)) + response = client.list_documents(parent=knowledge_base_path) + for document in response: + print(' - Display Name: {}'.format(document.display_name)) + print(' - Knowledge ID: {}'.format(document.name)) + print(' - MIME Type: {}'.format(document.mime_type)) + print(' - Knowledge Types:') + for knowledge_type in document.knowledge_types: + print(' - {}'.format(KNOWLEDGE_TYPES[knowledge_type])) + print(' - Source: {}\n'.format(document.content_uri)) + return response +# [END dialogflow_list_document] # [START dialogflow_create_document]] -def create_document( - project_id, knowledge_base_id, display_name, mime_type, knowledge_type, content_uri -): +def create_document(project_id, knowledge_base_id, display_name, mime_type, + knowledge_type, content_uri): """Creates a Document. Args: @@ -48,84 +81,140 @@ def create_document( content_uri: Uri of the document, e.g. gs://path/mydoc.csv, http://mypage.com/faq.html.""" from google.cloud import dialogflow_v2beta1 as dialogflow - client = dialogflow.DocumentsClient() knowledge_base_path = dialogflow.KnowledgeBasesClient.knowledge_base_path( - project_id, knowledge_base_id - ) + project_id, knowledge_base_id) document = dialogflow.Document( - display_name=display_name, mime_type=mime_type, content_uri=content_uri - ) + display_name=display_name, mime_type=mime_type, + content_uri=content_uri) document.knowledge_types.append( getattr(dialogflow.Document.KnowledgeType, knowledge_type) ) response = client.create_document(parent=knowledge_base_path, document=document) - print("Waiting for results...") + print('Waiting for results...') document = response.result(timeout=120) - print("Created Document:") - print(" - Display Name: {}".format(document.display_name)) - print(" - Knowledge ID: {}".format(document.name)) - print(" - MIME Type: {}".format(document.mime_type)) - print(" - Knowledge Types:") + print('Created Document:') + print(' - Display Name: {}'.format(document.display_name)) + print(' - Knowledge ID: {}'.format(document.name)) + print(' - MIME Type: {}'.format(document.mime_type)) + print(' - Knowledge Types:') for knowledge_type in document.knowledge_types: - print(" - {}".format(KNOWLEDGE_TYPES[knowledge_type])) - print(" - Source: {}\n".format(document.content_uri)) + print(' - {}'.format(KNOWLEDGE_TYPES[knowledge_type])) + print(' - Source: {}\n'.format(document.content_uri)) +# [END dialogflow_create_document] + + +# [START dialogflow_get_document]] +def get_document(project_id, knowledge_base_id, document_id): + """Gets a Document. + + Args: + project_id: The GCP project linked with the agent. + knowledge_base_id: Id of the Knowledge base. + document_id: Id of the Document.""" + from google.cloud import dialogflow_v2beta1 as dialogflow + client = dialogflow.DocumentsClient() + document_path = client.document_path(project_id, knowledge_base_id, + document_id) + + response = client.get_document(name=document_path) + print('Got Document:') + print(' - Display Name: {}'.format(response.display_name)) + print(' - Knowledge ID: {}'.format(response.name)) + print(' - MIME Type: {}'.format(response.mime_type)) + print(' - Knowledge Types:') + for knowledge_type in response.knowledge_types: + print(' - {}'.format(KNOWLEDGE_TYPES[knowledge_type])) + print(' - Source: {}\n'.format(response.content_uri)) + return response +# [END dialogflow_get_document]] + + +# [START dialogflow_delete_document]] +def delete_document(project_id, knowledge_base_id, document_id): + """Deletes a Document. + Args: + project_id: The GCP project linked with the agent. + knowledge_base_id: Id of the Knowledge base. + document_id: Id of the Document.""" + from google.cloud import dialogflow_v2beta1 as dialogflow + client = dialogflow.DocumentsClient() + document_path = client.document_path(project_id, knowledge_base_id, + document_id) -# [END dialogflow_create_document]] + response = client.delete_document(name=document_path) + print('operation running:\n {}'.format(response.operation)) + print('Waiting for results...') + print('Done.\n {}'.format(response.result())) +# [END dialogflow_delete_document]] -if __name__ == "__main__": +if __name__ == '__main__': parser = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter - ) - parser.add_argument("--project-id", help="Project id. Required.", required=True) + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( - "--knowledge-base-id", - help="The id of the Knowledge Base that the Document belongs to", - required=True, - ) + '--project-id', help='Project id. Required.', required=True) + parser.add_argument( + '--knowledge-base-id', + help='The id of the Knowledge Base that the Document belongs to', + required=True) - subparsers = parser.add_subparsers(dest="command") + subparsers = parser.add_subparsers(dest='command') + + list_parser = subparsers.add_parser( + 'list', + help='List all Documents that belong to a certain Knowledge base.') create_parser = subparsers.add_parser( - "create", help="Create a Document for a certain Knowledge base." - ) + 'create', help='Create a Document for a certain Knowledge base.') create_parser.add_argument( - "--display-name", - help="A name of the Document, mainly used for display purpose, " - "can not be used to identify the Document.", - default=str(""), - ) + '--display-name', + help='A name of the Document, mainly used for display purpose, ' + 'can not be used to identify the Document.', + default=str('')) create_parser.add_argument( - "--mime-type", - help="The mime-type of the Document, e.g. text/csv, text/html, " - "text/plain, text/pdf etc. ", - required=True, - ) + '--mime-type', + help='The mime-type of the Document, e.g. text/csv, text/html, ' + 'text/plain, text/pdf etc. ', + required=True) create_parser.add_argument( - "--knowledge-type", - help="The knowledge-type of the Document, e.g. FAQ, EXTRACTIVE_QA.", - required=True, - ) + '--knowledge-type', + help='The knowledge-type of the Document, e.g. FAQ, EXTRACTIVE_QA.', + required=True) create_parser.add_argument( - "--content-uri", - help="The uri of the Document, e.g. gs://path/mydoc.csv, " - "http://mypage.com/faq.html", - required=True, - ) + '--content-uri', + help='The uri of the Document, e.g. gs://path/mydoc.csv, ' + 'http://mypage.com/faq.html', + required=True) + + get_parser = subparsers.add_parser( + 'get', help='Get a Document by its id and the Knowledge base id.') + get_parser.add_argument( + '--document-id', help='The id of the Document', required=True) + + delete_parser = subparsers.add_parser( + 'delete', help='Delete a Document by its id and the Knowledge base' + 'id.') + delete_parser.add_argument( + '--document-id', + help='The id of the Document you want to delete', + required=True) args = parser.parse_args() - if args.command == "create": - create_document( - args.project_id, - args.knowledge_base_id, - args.display_name, - args.mime_type, - args.knowledge_type, - args.content_uri, - ) + if args.command == 'list': + list_documents(args.project_id, args.knowledge_base_id) + elif args.command == 'create': + create_document(args.project_id, args.knowledge_base_id, + args.display_name, args.mime_type, args.knowledge_type, + args.content_uri) + elif args.command == 'get': + get_document(args.project_id, args.knowledge_base_id, args.document_id) + elif args.command == 'delete': + delete_document(args.project_id, args.knowledge_base_id, + args.document_id) diff --git a/samples/snippets/knowledge_base_management.py b/samples/snippets/knowledge_base_management.py index 644a95f0e..d33044456 100644 --- a/samples/snippets/knowledge_base_management.py +++ b/samples/snippets/knowledge_base_management.py @@ -19,7 +19,13 @@ Examples: python knowledge_base_management.py -h python knowledge_base_management.py --project-id PROJECT_ID \ + list + python knowledge_base_management.py --project-id PROJECT_ID \ create --display-name DISPLAY_NAME + python knowledge_base_management.py --project-id PROJECT_ID \ + get --knowledge-base-id knowledge_base_id + python knowledge_base_management.py --project-id PROJECT_ID \ + delete --knowledge-base-id knowledge_base_id """ import argparse @@ -33,41 +39,100 @@ def create_knowledge_base(project_id, display_name): project_id: The GCP project linked with the agent. display_name: The display name of the Knowledge base.""" from google.cloud import dialogflow_v2beta1 as dialogflow - client = dialogflow.KnowledgeBasesClient() project_path = client.common_project_path(project_id) - knowledge_base = dialogflow.KnowledgeBase(display_name=display_name) + knowledge_base = dialogflow.KnowledgeBase( + display_name=display_name) response = client.create_knowledge_base( - parent=project_path, knowledge_base=knowledge_base + parent=project_path, + knowledge_base=knowledge_base ) - print("Knowledge Base created:\n") - print("Display Name: {}\n".format(response.display_name)) - print("Knowledge ID: {}\n".format(response.name)) + print('Knowledge Base created:\n') + print('Display Name: {}\n'.format(response.display_name)) + print('Knowledge ID: {}\n'.format(response.name)) +# [END dialogflow_create_knowledge_base] -# [END dialogflow_create_knowledge_base] +# [START dialogflow_get_knowledge_base] +def get_knowledge_base(project_id, knowledge_base_id): + """Gets a specific Knowledge base. + + Args: + project_id: The GCP project linked with the agent. + knowledge_base_id: Id of the Knowledge base.""" + from google.cloud import dialogflow_v2beta1 as dialogflow + client = dialogflow.KnowledgeBasesClient() + knowledge_base_path = client.knowledge_base_path( + project_id, knowledge_base_id) + + response = client.get_knowledge_base(name=knowledge_base_path) + + print('Got Knowledge Base:') + print(' - Display Name: {}'.format(response.display_name)) + print(' - Knowledge ID: {}'.format(response.name)) + return response +# [END dialogflow_get_knowledge_base] -if __name__ == "__main__": +# [START dialogflow_delete_knowledge_base] +def delete_knowledge_base(project_id, knowledge_base_id): + """Deletes a specific Knowledge base. + + Args: + project_id: The GCP project linked with the agent. + knowledge_base_id: Id of the Knowledge base.""" + from google.cloud import dialogflow_v2beta1 as dialogflow + client = dialogflow.KnowledgeBasesClient() + knowledge_base_path = client.knowledge_base_path( + project_id, knowledge_base_id) + + client.delete_knowledge_base(name=knowledge_base_path) + + print('Knowledge Base deleted.') +# [END dialogflow_delete_knowledge_base] + + +if __name__ == '__main__': parser = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter - ) - parser.add_argument("--project-id", help="Project/agent id.", required=True) + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + '--project-id', help='Project/agent id.', required=True) + + subparsers = parser.add_subparsers(dest='command') - subparsers = parser.add_subparsers(dest="command") + list_parser = subparsers.add_parser( + 'list', help='List all Knowledge bases that belong to the project.') - create_parser = subparsers.add_parser("create", help="Create a new Knowledge base.") + create_parser = subparsers.add_parser( + 'create', help='Create a new Knowledge base.') create_parser.add_argument( - "--display-name", - help="A name of the Knowledge base, used for display purpose, " - "can not be used to identify the Knowledge base.", - default=str(""), - ) + '--display-name', + help='A name of the Knowledge base, used for display purpose, ' + 'can not be used to identify the Knowledge base.', + default=str('')) + + get_parser = subparsers.add_parser( + 'get', help='Get a Knowledge base by its id.') + get_parser.add_argument( + '--knowledge-base-id', help='The id of the Knowledge base.', + required=True) + + delete_parser = subparsers.add_parser( + 'delete', help='Delete a Knowledge base by its id.') + delete_parser.add_argument( + '--knowledge-base-id', + help='The id of the Knowledge base you want to delete.', + required=True) args = parser.parse_args() - if args.command == "create": + if args.command == 'create': create_knowledge_base(args.project_id, args.display_name) + elif args.command == 'get': + get_knowledge_base(args.project_id, args.knowledge_base_id) + elif args.command == 'delete': + delete_knowledge_base(args.project_id, args.knowledge_base_id) diff --git a/samples/snippets/participant_management.py b/samples/snippets/participant_management.py new file mode 100644 index 000000000..f04b4c716 --- /dev/null +++ b/samples/snippets/participant_management.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Dialogflow API Python sample showing how to manage Participants. +""" + +from google.cloud import dialogflow_v2beta1 as dialogflow + +ROLES = ['HUMAN_AGENT', 'AUTOMATED_AGENT', 'END_USER'] + + +# [START dialogflow_create_participant] +def create_participant(project_id, conversation_id, role): + """Creates a participant in a given conversation. + + Args: + project_id: The GCP project linked with the conversation profile. + conversation_id: Id of the conversation. + participant: participant to be created.""" + + client = dialogflow.ParticipantsClient() + conversation_path = dialogflow.ConversationsClient.conversation_path( + project_id, conversation_id) + if role in ROLES: + response = client.create_participant(parent=conversation_path, + participant={'role': role}) + print('Participant Created.') + print('Role: {}'.format(response.role)) + print('Name: {}'.format(response.name)) + + return response + + +# [END dialogflow_create_participant] + + +# [START dialogflow_analyze_content_text] +def analyze_content_text(project_id, conversation_id, participant_id, text): + """Analyze text message content from a participant. + + Args: + project_id: The GCP project linked with the conversation profile. + conversation_id: Id of the conversation. + participant_id: Id of the participant. + text: the text message that participant typed.""" + + client = dialogflow.ParticipantsClient() + participant_path = client.participant_path(project_id, conversation_id, + participant_id) + text_input = {'text': text, 'language_code': 'en-US'} + response = client.analyze_content(participant=participant_path, + text_input=text_input) + print('AnalyzeContent Response:') + print('Reply Text: {}'.format(response.reply_text)) + + for suggestion_result in response.human_agent_suggestion_results: + if suggestion_result.error is not None: + print('Error: {}'.format(suggestion_result.error.message)) + if suggestion_result.suggest_articles_response: + for answer in suggestion_result.suggest_articles_response.article_answers: + print('Article Suggestion Answer: {}'.format(answer.title)) + print('Answer Record: {}'.format(answer.answer_record)) + if suggestion_result.suggest_faq_answers_response: + for answer in suggestion_result.suggest_faq_answers_response.faq_answers: + print('Faq Answer: {}'.format(answer.answer)) + print('Answer Record: {}'.format(answer.answer_record)) + if suggestion_result.suggest_smart_replies_response: + for answer in suggestion_result.suggest_smart_replies_response.smart_reply_answers: + print('Smart Reply: {}'.format(answer.reply)) + print('Answer Record: {}'.format(answer.answer_record)) + + for suggestion_result in response.end_user_suggestion_results: + if suggestion_result.error: + print('Error: {}'.format(suggestion_result.error.message)) + if suggestion_result.suggest_articles_response: + for answer in suggestion_result.suggest_articles_response.article_answers: + print('Article Suggestion Answer: {}'.format(answer.title)) + print('Answer Record: {}'.format(answer.answer_record)) + if suggestion_result.suggest_faq_answers_response: + for answer in suggestion_result.suggest_faq_answers_response.faq_answers: + print('Faq Answer: {}'.format(answer.answer)) + print('Answer Record: {}'.format(answer.answer_record)) + if suggestion_result.suggest_smart_replies_response: + for answer in suggestion_result.suggest_smart_replies_response.smart_reply_answers: + print('Smart Reply: {}'.format(answer.reply)) + print('Answer Record: {}'.format(answer.answer_record)) + + return response + + +# [END dialogflow_analyze_content_text] diff --git a/samples/snippets/participant_management_test.py b/samples/snippets/participant_management_test.py new file mode 100644 index 000000000..b2a0563ff --- /dev/null +++ b/samples/snippets/participant_management_test.py @@ -0,0 +1,144 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import conversation_management +import conversation_profile_management +import document_management +import knowledge_base_management +import participant_management + +PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT') +KNOWLEDGE_BASE_DISPLAY_NAME = 'fake_KNOWLEDGE_BASE_DISPLAY_NAME' +DOCUMENT_DISPLAY_NAME = 'Cancel an order' +CONVERSATION_PROFILE_DISPLAY_NAME = 'fake_conversation_profile' + + +def test_analyze_content_text(capsys): + """Test analyze content api with text only messages. + """ + # Create knowledge base. + knowledge_base_management.create_knowledge_base( + PROJECT_ID, KNOWLEDGE_BASE_DISPLAY_NAME) + out, _ = capsys.readouterr() + knowledge_base_id = out.split('knowledgeBases/')[1].rstrip() + # Get the knowledge base + knowledge_base_management.get_knowledge_base(PROJECT_ID, knowledge_base_id) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format(KNOWLEDGE_BASE_DISPLAY_NAME) in out + + # Create documents. Note that you should get read permission of bucket gs://ruogu/parsed_5_24/7157212.html + # via Pantheon for service account (google application credential account) from here: + # https://pantheon.corp.google.com/storage/browser/ruogu/parsed_5_24/?project=agent-assistant-demo + document_management.create_document(PROJECT_ID, knowledge_base_id, + DOCUMENT_DISPLAY_NAME, 'text/html', + 'ARTICLE_SUGGESTION', + 'gs://ruogu/parsed_5_24/7157212.html') + out, _ = capsys.readouterr() + document_id = out.split('documents/')[1].split(' - MIME Type:')[0].rstrip() + + # Get the Document + document_management.get_document(PROJECT_ID, knowledge_base_id, + document_id) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format(DOCUMENT_DISPLAY_NAME) in out + + # Create conversation profile. + conversation_profile_management.create_conversation_profile_article_faq( + project_id=PROJECT_ID, + display_name=CONVERSATION_PROFILE_DISPLAY_NAME, + article_suggestion_knowledge_base_id=knowledge_base_id) + + out, _ = capsys.readouterr() + assert 'Display Name: {}'.format(CONVERSATION_PROFILE_DISPLAY_NAME) in out + conversation_profile_id = out.split('conversationProfiles/')[1].rstrip() + + # Create conversation. + conversation_management.create_conversation( + project_id=PROJECT_ID, conversation_profile_id=conversation_profile_id) + + out, _ = capsys.readouterr() + conversation_id = out.split('conversations/')[1].rstrip() + + # Create end user participant. + participant_management.create_participant(project_id=PROJECT_ID, + conversation_id=conversation_id, + role='END_USER') + out, _ = capsys.readouterr() + end_user_id = out.split('participants/')[1].rstrip() + + # Create human agent participant. + participant_management.create_participant(project_id=PROJECT_ID, + conversation_id=conversation_id, + role='HUMAN_AGENT') + out, _ = capsys.readouterr() + human_agent_id = out.split('participants/')[1].rstrip() + + # AnalyzeContent + participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=human_agent_id, + text='Hi, how are you?') + out, _ = capsys.readouterr() + + participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=end_user_id, + text='Hi, I am doing well, how about you?') + out, _ = capsys.readouterr() + + participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=human_agent_id, + text='Great. How can I help you?') + out, _ = capsys.readouterr() + + participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=end_user_id, + text='So I ordered something, but I do not like it.') + out, _ = capsys.readouterr() + + participant_management.analyze_content_text( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=end_user_id, + text='Thinking if I can cancel that order') + suggestion_out, _ = capsys.readouterr() + # Currently suggestion_out won't contain the suggestion we want since it + # takes time for document to be ready to serve. + # assert 'Cancel an order' in suggestion_out + + # Complete conversation. + conversation_management.complete_conversation( + project_id=PROJECT_ID, conversation_id=conversation_id) + + # Delete conversation profile. + conversation_profile_management.delete_conversation_profile( + project_id=PROJECT_ID, conversation_profile_id=conversation_profile_id) + + # Delete document. + document_management.delete_document(PROJECT_ID, knowledge_base_id, + document_id) + + # Delete the Knowledge Base. + knowledge_base_management.delete_knowledge_base(PROJECT_ID, + knowledge_base_id) diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt index c250f5c85..79820d6bc 100644 --- a/samples/snippets/requirements.txt +++ b/samples/snippets/requirements.txt @@ -1 +1 @@ -google-cloud-dialogflow==2.0.0 +google-cloud-dialogflow==2.1.0