diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6a72efec1851..1680fc1c38ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -43,6 +43,7 @@ /datalabeling/**/* @GoogleCloudPlatform/python-samples-reviewers @ivanmkc /dataproc/**/* @GoogleCloudPlatform/python-samples-reviewers /datastore/**/* @GoogleCloudPlatform/cloud-native-db-dpes @GoogleCloudPlatform/python-samples-reviewers +/dialogflow/**/* @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/python-samples-reviewers /dns/**/* @GoogleCloudPlatform/python-samples-reviewers /documentai/**/* @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/python-samples-reviewers /endpoints/**/* @GoogleCloudPlatform/python-samples-reviewers diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index 46c13c453ca2..75b1f0c8808b 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -94,6 +94,7 @@ assign_issues_by: - 'api: language' - 'api: texttospeech' - 'api: retail' + - 'api: dialogflow' to: - GoogleCloudPlatform/dee-data-ai - labels: diff --git a/dialogflow/README.rst b/dialogflow/README.rst new file mode 100644 index 000000000000..b52a75d7dff6 --- /dev/null +++ b/dialogflow/README.rst @@ -0,0 +1,465 @@ +.. This file is automatically generated. Do not edit this file directly. + +Dialogflow Enterprise Edition API Python Samples +=============================================================================== + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/README.rst + + +This directory contains samples for Dialogflow Enterprise Edition API. The `Dialogflow Enterprise Edition API`_ enables you to create conversational experiences across devices and platforms. + + + + +.. _Dialogflow Enterprise Edition API: https://cloud.google.com/dialogflow-enterprise/docs/ + + + + + +Setup +------------------------------------------------------------------------------- + + +Authentication +++++++++++++++ + +This sample requires you to have authentication setup. Refer to the +`Authentication Getting Started Guide`_ for instructions on setting up +credentials for applications. + +.. _Authentication Getting Started Guide: + https://cloud.google.com/docs/authentication/getting-started + +Install Dependencies +++++++++++++++++++++ + +#. Clone python-docs-samples and change directory to the sample directory you want to use. + + .. code-block:: bash + + $ git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git + +#. Install `pip`_ and `virtualenv`_ if you do not already have them. You may want to refer to the `Python Development Environment Setup Guide`_ for Google Cloud Platform for instructions. + + .. _Python Development Environment Setup Guide: + https://cloud.google.com/python/setup + +#. Create a virtualenv. Samples are compatible with Python 3.6+. + + .. code-block:: bash + + $ virtualenv env + $ source env/bin/activate + +#. Install the dependencies needed to run the samples. + + .. code-block:: bash + + $ pip install -r requirements.txt + +.. _pip: https://pip.pypa.io/ +.. _virtualenv: https://virtualenv.pypa.io/ + +Samples +------------------------------------------------------------------------------- + +Detect Intent Text ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/detect_intent_texts.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python detect_intent_texts.py + + usage: detect_intent_texts.py [-h] --project-id PROJECT_ID + [--session-id SESSION_ID] + [--language-code LANGUAGE_CODE] + texts [texts ...] + + DialogFlow API Detect Intent Python sample with text inputs. + + Examples: + python detect_intent_texts.py -h + python detect_intent_texts.py --project-id PROJECT_ID --session-id SESSION_ID "hello" "book a meeting room" "Mountain View" + python detect_intent_texts.py --project-id PROJECT_ID --session-id SESSION_ID "tomorrow" "10 AM" "2 hours" "10 people" "A" "yes" + + positional arguments: + texts Text inputs. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + --session-id SESSION_ID + Identifier of the DetectIntent session. Defaults to a + random UUID. + --language-code LANGUAGE_CODE + Language code of the query. Defaults to "en-US". + + + +Detect Intent Audio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/detect_intent_audio.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python detect_intent_audio.py + + usage: detect_intent_audio.py [-h] --project-id PROJECT_ID + [--session-id SESSION_ID] + [--language-code LANGUAGE_CODE] + --audio-file-path AUDIO_FILE_PATH + + DialogFlow API Detect Intent Python sample with audio file. + + Examples: + python detect_intent_audio.py -h + python detect_intent_audio.py --project-id PROJECT_ID --session-id SESSION_ID --audio-file-path resources/book_a_room.wav + python detect_intent_audio.py --project-id PROJECT_ID --session-id SESSION_ID --audio-file-path resources/mountain_view.wav + python detect_intent_audio.py --project-id PROJECT_ID --session-id SESSION_ID --audio-file-path resources/today.wav + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + --session-id SESSION_ID + Identifier of the DetectIntent session. Defaults to a + random UUID. + --language-code LANGUAGE_CODE + Language code of the query. Defaults to "en-US". + --audio-file-path AUDIO_FILE_PATH + Path to the audio file. + + + +Detect Intent Stream ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/detect_intent_stream.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python detect_intent_stream.py + + usage: detect_intent_stream.py [-h] --project-id PROJECT_ID + [--session-id SESSION_ID] + [--language-code LANGUAGE_CODE] + --audio-file-path AUDIO_FILE_PATH + + DialogFlow API Detect Intent Python sample with audio files processed + as an audio stream. + + Examples: + python detect_intent_stream.py -h + python detect_intent_stream.py --project-id PROJECT_ID --session-id SESSION_ID --audio-file-path resources/book_a_room.wav + python detect_intent_stream.py --project-id PROJECT_ID --session-id SESSION_ID --audio-file-path resources/mountain_view.wav + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + --session-id SESSION_ID + Identifier of the DetectIntent session. Defaults to a + random UUID. + --language-code LANGUAGE_CODE + Language code of the query. Defaults to "en-US". + --audio-file-path AUDIO_FILE_PATH + Path to the audio file. + + + +Detect Intent Knowledge Base ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/detect_intent_knowledge.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python detect_intent_knowledge.py + + usage: detect_intent_knowledge.py [-h] --project-id PROJECT_ID + [--session-id SESSION_ID] + [--language-code LANGUAGE_CODE] + --knowledge-base-id KNOWLEDGE_BASE_ID + texts [texts ...] + + Dialogflow API Detect Knowledge Base Intent Python sample with text inputs. + + Examples: + python detect_intent_knowledge.py -h + python detect_intent_knowledge.py --project-id PROJECT_ID --session-id SESSION_ID --knowledge-base-id KNOWLEDGE_BASE_ID "hello" "how do I reset my password?" + + positional arguments: + texts Text inputs. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + --session-id SESSION_ID + ID of the DetectIntent session. Defaults to a random + UUID. + --language-code LANGUAGE_CODE + Language code of the query. Defaults to "en-US". + --knowledge-base-id KNOWLEDGE_BASE_ID + The id of the Knowledge Base to query against + + + +Detect Intent with Sentiment Analysis ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/detect_intent_with_sentiment_analysis.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python detect_intent_with_sentiment_analysis.py + + usage: detect_intent_with_sentiment_analysis.py [-h] --project-id PROJECT_ID + [--session-id SESSION_ID] + [--language-code LANGUAGE_CODE] + texts [texts ...] + + Dialogflow API Beta Detect Intent Python sample with sentiment analysis. + + Examples: + python detect_intent_with_sentiment_analysis.py -h + python detect_intent_with_sentiment_analysis.py --project-id PROJECT_ID --session-id SESSION_ID "hello" "book a meeting room" "Mountain View" + + positional arguments: + texts Text inputs. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + --session-id SESSION_ID + Identifier of the DetectIntent session. Defaults to a + random UUID. + --language-code LANGUAGE_CODE + Language code of the query. Defaults to "en-US". + + + +Detect Intent with Text to Speech Response ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/detect_intent_with_texttospeech_response.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python detect_intent_with_texttospeech_response.py + + usage: detect_intent_with_texttospeech_response.py [-h] --project-id + PROJECT_ID + [--session-id SESSION_ID] + [--language-code LANGUAGE_CODE] + texts [texts ...] + + Dialogflow API Beta Detect Intent Python sample with an audio response. + + Examples: + python detect_intent_with_texttospeech_response_test.py -h + python detect_intent_with_texttospeech_response_test.py --project-id PROJECT_ID --session-id SESSION_ID "hello" + + positional arguments: + texts Text inputs. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + --session-id SESSION_ID + Identifier of the DetectIntent session. Defaults to a + random UUID. + --language-code LANGUAGE_CODE + Language code of the query. Defaults to "en-US". + + + +Intent Management ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/intent_management.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python intent_management.py + + usage: intent_management.py [-h] --project-id PROJECT_ID + {list,create,delete} ... + + DialogFlow API Intent Python sample showing how to manage intents. + + Examples: + python intent_management.py -h + python intent_management.py --project-id PROJECT_ID list + python intent_management.py --project-id PROJECT_ID create "room.cancellation - yes" --training-phrases-parts "cancel" "cancellation" --message-texts "Are you sure you want to cancel?" "Cancelled." + python intent_management.py --project-id PROJECT_ID delete 74892d81-7901-496a-bb0a-c769eda5180e + + positional arguments: + {list,create,delete} + list + create Create an intent of the given intent type. + delete Delete intent with the given intent type and intent + value. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. Required. + + + +Knowledge Base Management ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/knowledge_base_management.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python knowledge_base_management.py + + usage: knowledge_base_management.py [-h] --project-id PROJECT_ID + {list,create,get,delete} ... + + Dialogflow API Python sample showing how to manage Knowledge bases. + + 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 + + positional arguments: + {list,create,get,delete} + list List all Knowledge bases that belong to the project. + create Create a new Knowledge base. + get Get a Knowledge base by its id. + delete Delete a Knowledge base by its id. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project/agent id. + + + +Document Management ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +.. image:: https://gstatic.com/cloudssh/images/open-btn.png + :target: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=/document_management.py,/README.rst + + + + +To run this sample: + +.. code-block:: bash + + $ python document_management.py + + usage: document_management.py [-h] --project-id PROJECT_ID --knowledge-base-id + KNOWLEDGE_BASE_ID + {list,create,get,delete} ... + + Dialogflow API Python sample showing how to manage Knowledge Documents. + + Examples: + 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 + + positional arguments: + {list,create,get,delete} + list List all Documents that belong to a certain Knowledge + base. + create Create a Document for a certain Knowledge base. + get Get a Document by its id and the Knowledge base id. + delete Delete a Document by its id and the Knowledge baseid. + + optional arguments: + -h, --help show this help message and exit + --project-id PROJECT_ID + Project id. Required. + --knowledge-base-id KNOWLEDGE_BASE_ID + The id of the Knowledge Base that the Document belongs + to + + + + + +The client library +------------------------------------------------------------------------------- + +This sample uses the `Google Cloud Client Library for Python`_. +You can read the documentation for more details on API usage and use GitHub +to `browse the source`_ and `report issues`_. + +.. _Google Cloud Client Library for Python: + https://googlecloudplatform.github.io/google-cloud-python/ +.. _browse the source: + https://github.com/GoogleCloudPlatform/google-cloud-python +.. _report issues: + https://github.com/GoogleCloudPlatform/google-cloud-python/issues + + +.. _Google Cloud SDK: https://cloud.google.com/sdk/ \ No newline at end of file diff --git a/dialogflow/README.rst.in b/dialogflow/README.rst.in new file mode 100644 index 000000000000..4be2f893f5a5 --- /dev/null +++ b/dialogflow/README.rst.in @@ -0,0 +1,43 @@ +# This file is used to generate README.rst + +product: + name: Dialogflow Enterprise Edition API + short_name: Dialogflow API + url: https://cloud.google.com/dialogflow-enterprise/docs/ + description: > + The `Dialogflow Enterprise Edition API`_ enables you to create conversational experiences across devices and platforms. + +setup: +- auth +- install_deps + +samples: +- name: Detect Intent Text + file: detect_intent_texts.py + show_help: True +- name: Detect Intent Audio + file: detect_intent_audio.py + show_help: True +- name: Detect Intent Stream + file: detect_intent_stream.py + show_help: True +- name: Detect Intent Knowledge Base + file: detect_intent_knowledge.py + show_help: True +- name: Detect Intent with Sentiment Analysis + file: detect_intent_with_sentiment_analysis.py + show_help: True +- name: Detect Intent with Text to Speech Response + file: detect_intent_with_texttospeech_response.py + show_help: True +- name: Intent Management + file: intent_management.py + show_help: True +- name: Knowledge Base Management + file: knowledge_base_management.py + show_help: True +- name: Document Management + file: document_management.py + show_help: True + +cloud_client_library: true diff --git a/dialogflow/analyze_content_stream_test.py b/dialogflow/analyze_content_stream_test.py new file mode 100644 index 000000000000..29aa40b0fa13 --- /dev/null +++ b/dialogflow/analyze_content_stream_test.py @@ -0,0 +1,86 @@ +# Copyright 2022 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 uuid + +import pytest + +import conversation_management +import conversation_profile_management +import participant_management + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +AUDIO_FILE_PATH = "{0}/resources/book_a_room.wav".format( + os.path.realpath(os.path.dirname(__file__)), +) + + +@pytest.fixture +def conversation_profile_display_name(): + return f"sample_conversation_profile_{uuid.uuid4()}" + + +@pytest.fixture +def conversation_profile_id(conversation_profile_display_name): + # Create conversation profile. + response = conversation_profile_management.create_conversation_profile_article_faq( + project_id=PROJECT_ID, display_name=conversation_profile_display_name + ) + conversation_profile_id = response.name.split("conversationProfiles/")[1].rstrip() + + yield conversation_profile_id + + # Delete the conversation profile. + conversation_profile_management.delete_conversation_profile( + PROJECT_ID, conversation_profile_id + ) + + +@pytest.fixture +def conversation_id(conversation_profile_id): + # Create conversation. + response = conversation_management.create_conversation( + project_id=PROJECT_ID, conversation_profile_id=conversation_profile_id + ) + conversation_id = response.name.split("conversations/")[1].rstrip() + + yield conversation_id + + # Complete the conversation. + conversation_management.complete_conversation( + project_id=PROJECT_ID, conversation_id=conversation_id + ) + + +@pytest.fixture +def participant_id(conversation_id): + response = participant_management.create_participant( + project_id=PROJECT_ID, conversation_id=conversation_id, role="END_USER" + ) + participant_id = response.name.split("participants/")[1].rstrip() + yield participant_id + + +# Test live transcription with streaming_analyze_content. +def test_analyze_content_audio_stream(capsys, conversation_id, participant_id): + # Call StreamingAnalyzeContent to transcribe the audio. + participant_management.analyze_content_audio_stream( + project_id=PROJECT_ID, + conversation_id=conversation_id, + participant_id=participant_id, + audio_file_path=AUDIO_FILE_PATH, + ) + out, _ = capsys.readouterr() + assert "book a room" in out diff --git a/dialogflow/conversation_management.py b/dialogflow/conversation_management.py new file mode 100644 index 000000000000..d85feea3a85b --- /dev/null +++ b/dialogflow/conversation_management.py @@ -0,0 +1,91 @@ +#!/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/dialogflow/conversation_profile_management.py b/dialogflow/conversation_profile_management.py new file mode 100644 index 000000000000..aed0ce6ddae5 --- /dev/null +++ b/dialogflow/conversation_profile_management.py @@ -0,0 +1,210 @@ +#!/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/dialogflow/conversation_profile_management_test.py b/dialogflow/conversation_profile_management_test.py new file mode 100644 index 000000000000..fb250897f942 --- /dev/null +++ b/dialogflow/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 conversation 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/dialogflow/create_document_test.py b/dialogflow/create_document_test.py new file mode 100644 index 000000000000..fed3c914e035 --- /dev/null +++ b/dialogflow/create_document_test.py @@ -0,0 +1,65 @@ +# Copyright 2020 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 uuid + +from google.cloud import dialogflow_v2beta1 as dialogflow +import pytest + +import document_management + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +KNOWLEDGE_BASE_NAME = "knowledge_{}".format(uuid.uuid4()) +DOCUMENT_DISPLAY_NAME = "test_document_{}".format(uuid.uuid4()) +pytest.KNOWLEDGE_BASE_ID = None + + +@pytest.fixture(scope="function", autouse=True) +def setup_teardown(): + # Create a knowledge base to use in document management + client = dialogflow.KnowledgeBasesClient() + project_path = client.common_project_path(PROJECT_ID) + 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.DeleteKnowledgeBaseRequest( + name=knowledge_base_path, force=True + ) + client.delete_knowledge_base(request=request) + + +@pytest.mark.flaky(max_runs=3, min_passes=1) +def test_create_document(capsys): + document_management.create_document( + PROJECT_ID, + pytest.KNOWLEDGE_BASE_ID, + DOCUMENT_DISPLAY_NAME, + "text/html", + "FAQ", + "https://cloud.google.com/storage/docs/faq", + ) + out, _ = capsys.readouterr() + assert DOCUMENT_DISPLAY_NAME in out diff --git a/dialogflow/create_knowledge_base_test.py b/dialogflow/create_knowledge_base_test.py new file mode 100644 index 000000000000..39d33d0f3786 --- /dev/null +++ b/dialogflow/create_knowledge_base_test.py @@ -0,0 +1,48 @@ +# Copyright 2020 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 uuid + +from google.cloud import dialogflow_v2beta1 +import pytest + +import knowledge_base_management + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +KNOWLEDGE_BASE_NAME = "knowledge_{}".format(uuid.uuid4()) +pytest.KNOWLEDGE_BASE_ID = None + + +@pytest.fixture(scope="function", autouse=True) +def teardown(): + yield + + # Delete the created knowledge base + client = dialogflow_v2beta1.KnowledgeBasesClient() + assert pytest.KNOWLEDGE_BASE_ID is not None + knowledge_base_path = client.knowledge_base_path( + PROJECT_ID, pytest.KNOWLEDGE_BASE_ID + ) + client.delete_knowledge_base(name=knowledge_base_path) + + +def test_create_knowledge_base(capsys): + knowledge_base_management.create_knowledge_base(PROJECT_ID, KNOWLEDGE_BASE_NAME) + out, _ = capsys.readouterr() + assert KNOWLEDGE_BASE_NAME in out + + pytest.KNOWLEDGE_BASE_ID = out.split("/knowledgeBases/")[1].split("\n")[0] diff --git a/dialogflow/detect_intent_audio.py b/dialogflow/detect_intent_audio.py new file mode 100644 index 000000000000..6c398168713e --- /dev/null +++ b/dialogflow/detect_intent_audio.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +# Copyright 2017 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 Detect Intent Python sample with audio file. + +Examples: + python detect_intent_audio.py -h + python detect_intent_audio.py --project-id PROJECT_ID \ + --session-id SESSION_ID --audio-file-path resources/book_a_room.wav + python detect_intent_audio.py --project-id PROJECT_ID \ + --session-id SESSION_ID --audio-file-path resources/mountain_view.wav + python detect_intent_audio.py --project-id PROJECT_ID \ + --session-id SESSION_ID --audio-file-path resources/today.wav +""" + +import argparse +import uuid + + +# [START dialogflow_detect_intent_audio] +def detect_intent_audio(project_id, session_id, audio_file_path, language_code): + """Returns the result of detect intent with an audio file as input. + + Using the same `session_id` between requests allows continuation + of the conversation.""" + from google.cloud import dialogflow + + session_client = dialogflow.SessionsClient() + + # Note: hard coding audio_encoding and sample_rate_hertz for simplicity. + audio_encoding = dialogflow.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + sample_rate_hertz = 16000 + + session = session_client.session_path(project_id, session_id) + print("Session path: {}\n".format(session)) + + with open(audio_file_path, "rb") as audio_file: + input_audio = audio_file.read() + + audio_config = dialogflow.InputAudioConfig( + audio_encoding=audio_encoding, + language_code=language_code, + sample_rate_hertz=sample_rate_hertz, + ) + query_input = dialogflow.QueryInput(audio_config=audio_config) + + request = dialogflow.DetectIntentRequest( + session=session, + query_input=query_input, + input_audio=input_audio, + ) + response = session_client.detect_intent(request=request) + + print("=" * 20) + print("Query text: {}".format(response.query_result.query_text)) + print( + "Detected intent: {} (confidence: {})\n".format( + response.query_result.intent.display_name, + response.query_result.intent_detection_confidence, + ) + ) + print("Fulfillment text: {}\n".format(response.query_result.fulfillment_text)) + + +# [END dialogflow_detect_intent_audio] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument( + "--session-id", + help="Identifier of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument( + "--audio-file-path", help="Path to the audio file.", required=True + ) + + args = parser.parse_args() + + detect_intent_audio( + args.project_id, args.session_id, args.audio_file_path, args.language_code + ) diff --git a/dialogflow/detect_intent_audio_test.py b/dialogflow/detect_intent_audio_test.py new file mode 100644 index 000000000000..84bb41cf2524 --- /dev/null +++ b/dialogflow/detect_intent_audio_test.py @@ -0,0 +1,37 @@ +# Copyright 2017 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 uuid + +from detect_intent_audio import detect_intent_audio + +DIRNAME = os.path.realpath(os.path.dirname(__file__)) +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +SESSION_ID = "test_{}".format(uuid.uuid4()) +AUDIOS = [ + "{0}/resources/book_a_room.wav".format(DIRNAME), + "{0}/resources/mountain_view.wav".format(DIRNAME), + "{0}/resources/today.wav".format(DIRNAME), +] + + +def test_detect_intent_audio(capsys): + for audio_file_path in AUDIOS: + detect_intent_audio(PROJECT_ID, SESSION_ID, audio_file_path, "en-US") + out, _ = capsys.readouterr() + + assert "Fulfillment text: What time will the meeting start?" in out diff --git a/dialogflow/detect_intent_knowledge.py b/dialogflow/detect_intent_knowledge.py new file mode 100644 index 000000000000..8ec6c9cca764 --- /dev/null +++ b/dialogflow/detect_intent_knowledge.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python + +# Copyright 2018 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 Detect Knowledge Base Intent Python sample with text inputs. + +Examples: + python detect_intent_knowledge.py -h + python detect_intent_knowledge.py --project-id PROJECT_ID \ + --session-id SESSION_ID --knowledge-base-id KNOWLEDGE_BASE_ID \ + "hello" "how do I reset my password?" +""" + +import argparse +import uuid + + +# [START dialogflow_detect_intent_knowledge] +def detect_intent_knowledge( + project_id, session_id, language_code, knowledge_base_id, texts +): + """Returns the result of detect intent with querying Knowledge Connector. + + Args: + project_id: The GCP project linked with the agent you are going to query. + session_id: Id of the session, using the same `session_id` between requests + allows continuation of the conversation. + language_code: Language of the queries. + knowledge_base_id: The Knowledge base's id to query against. + texts: A list of text queries to send. + """ + from google.cloud import dialogflow_v2beta1 as dialogflow + + session_client = dialogflow.SessionsClient() + + session_path = session_client.session_path(project_id, session_id) + print("Session path: {}\n".format(session_path)) + + for text in texts: + text_input = dialogflow.TextInput(text=text, language_code=language_code) + + query_input = dialogflow.QueryInput(text=text_input) + + knowledge_base_path = dialogflow.KnowledgeBasesClient.knowledge_base_path( + project_id, knowledge_base_id + ) + + query_params = dialogflow.QueryParameters( + knowledge_base_names=[knowledge_base_path] + ) + + request = dialogflow.DetectIntentRequest( + session=session_path, query_input=query_input, query_params=query_params + ) + response = session_client.detect_intent(request=request) + + print("=" * 20) + print("Query text: {}".format(response.query_result.query_text)) + print( + "Detected intent: {} (confidence: {})\n".format( + response.query_result.intent.display_name, + response.query_result.intent_detection_confidence, + ) + ) + print("Fulfillment text: {}\n".format(response.query_result.fulfillment_text)) + print("Knowledge results:") + knowledge_answers = response.query_result.knowledge_answers + for answers in knowledge_answers.answers: + print(" - Answer: {}".format(answers.answer)) + print(" - Confidence: {}".format(answers.match_confidence)) + + +# [END dialogflow_detect_intent_knowledge] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument( + "--session-id", + help="ID of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument( + "--knowledge-base-id", + help="The id of the Knowledge Base to query against", + required=True, + ) + parser.add_argument("texts", nargs="+", type=str, help="Text inputs.") + + args = parser.parse_args() + + detect_intent_knowledge( + args.project_id, + args.session_id, + args.language_code, + args.knowledge_base_id, + args.texts, + ) diff --git a/dialogflow/detect_intent_knowledge_test.py b/dialogflow/detect_intent_knowledge_test.py new file mode 100644 index 000000000000..1ca999a081bf --- /dev/null +++ b/dialogflow/detect_intent_knowledge_test.py @@ -0,0 +1,34 @@ +# Copyright 2020 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 uuid + +import detect_intent_knowledge + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +SESSION_ID = "session_{}".format(uuid.uuid4()) +KNOWLEDGE_BASE_ID = "MjEwMjE4MDQ3MDQwMDc0NTQ3Mg" +TEXTS = ["Where is my data stored?"] + + +def test_detect_intent_knowledge(capsys): + detect_intent_knowledge.detect_intent_knowledge( + PROJECT_ID, SESSION_ID, "en-us", KNOWLEDGE_BASE_ID, TEXTS + ) + + out, _ = capsys.readouterr() + assert "Knowledge results" in out diff --git a/dialogflow/detect_intent_stream.py b/dialogflow/detect_intent_stream.py new file mode 100644 index 000000000000..430d4b51fe59 --- /dev/null +++ b/dialogflow/detect_intent_stream.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +# Copyright 2017 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 Detect Intent Python sample with audio files processed +as an audio stream. + +Examples: + python detect_intent_stream.py -h + python detect_intent_stream.py --project-id PROJECT_ID \ + --session-id SESSION_ID --audio-file-path resources/book_a_room.wav + python detect_intent_stream.py --project-id PROJECT_ID \ + --session-id SESSION_ID --audio-file-path resources/mountain_view.wav +""" + +import argparse +import uuid + + +# [START dialogflow_detect_intent_streaming] +def detect_intent_stream(project_id, session_id, audio_file_path, language_code): + """Returns the result of detect intent with streaming audio as input. + + Using the same `session_id` between requests allows continuation + of the conversation.""" + from google.cloud import dialogflow + + session_client = dialogflow.SessionsClient() + + # Note: hard coding audio_encoding and sample_rate_hertz for simplicity. + audio_encoding = dialogflow.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + sample_rate_hertz = 16000 + + session_path = session_client.session_path(project_id, session_id) + print("Session path: {}\n".format(session_path)) + + def request_generator(audio_config, audio_file_path): + query_input = dialogflow.QueryInput(audio_config=audio_config) + + # The first request contains the configuration. + yield dialogflow.StreamingDetectIntentRequest( + session=session_path, query_input=query_input + ) + + # Here we are reading small chunks of audio data from a local + # audio file. In practice these chunks should come from + # an audio input device. + with open(audio_file_path, "rb") as audio_file: + while True: + chunk = audio_file.read(4096) + if not chunk: + break + # The later requests contains audio data. + yield dialogflow.StreamingDetectIntentRequest(input_audio=chunk) + + audio_config = dialogflow.InputAudioConfig( + audio_encoding=audio_encoding, + language_code=language_code, + sample_rate_hertz=sample_rate_hertz, + ) + + requests = request_generator(audio_config, audio_file_path) + responses = session_client.streaming_detect_intent(requests=requests) + + print("=" * 20) + for response in responses: + print( + 'Intermediate transcript: "{}".'.format( + response.recognition_result.transcript + ) + ) + + # Note: The result from the last response is the final transcript along + # with the detected content. + query_result = response.query_result + + print("=" * 20) + print("Query text: {}".format(query_result.query_text)) + print( + "Detected intent: {} (confidence: {})\n".format( + query_result.intent.display_name, query_result.intent_detection_confidence + ) + ) + print("Fulfillment text: {}\n".format(query_result.fulfillment_text)) + + +# [END dialogflow_detect_intent_streaming] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument( + "--session-id", + help="Identifier of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument( + "--audio-file-path", help="Path to the audio file.", required=True + ) + + args = parser.parse_args() + + detect_intent_stream( + args.project_id, args.session_id, args.audio_file_path, args.language_code + ) diff --git a/dialogflow/detect_intent_stream_test.py b/dialogflow/detect_intent_stream_test.py new file mode 100644 index 000000000000..22b62b37977e --- /dev/null +++ b/dialogflow/detect_intent_stream_test.py @@ -0,0 +1,34 @@ +# Copyright 2017 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 uuid + +from detect_intent_stream import detect_intent_stream + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +SESSION_ID = "test_{}".format(uuid.uuid4()) +AUDIO_FILE_PATH = "{0}/resources/book_a_room.wav".format( + os.path.realpath(os.path.dirname(__file__)), +) + + +def test_detect_intent_stream(capsys): + detect_intent_stream(PROJECT_ID, SESSION_ID, AUDIO_FILE_PATH, "en-US") + out, _ = capsys.readouterr() + + assert "Intermediate transcript:" in out + assert "Fulfillment text:" in out diff --git a/dialogflow/detect_intent_texts.py b/dialogflow/detect_intent_texts.py new file mode 100644 index 000000000000..01cc2b95d056 --- /dev/null +++ b/dialogflow/detect_intent_texts.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python + +# Copyright 2017 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 Detect Intent Python sample with text inputs. + +Examples: + python detect_intent_texts.py -h + python detect_intent_texts.py --project-id PROJECT_ID \ + --session-id SESSION_ID \ + "hello" "book a meeting room" "Mountain View" + python detect_intent_texts.py --project-id PROJECT_ID \ + --session-id SESSION_ID \ + "tomorrow" "10 AM" "2 hours" "10 people" "A" "yes" +""" + +import argparse +import uuid + + +# [START dialogflow_es_detect_intent_text] +def detect_intent_texts(project_id, session_id, texts, language_code): + """Returns the result of detect intent with texts as inputs. + + Using the same `session_id` between requests allows continuation + of the conversation.""" + from google.cloud import dialogflow + + session_client = dialogflow.SessionsClient() + + session = session_client.session_path(project_id, session_id) + print("Session path: {}\n".format(session)) + + for text in texts: + text_input = dialogflow.TextInput(text=text, language_code=language_code) + + query_input = dialogflow.QueryInput(text=text_input) + + response = session_client.detect_intent( + request={"session": session, "query_input": query_input} + ) + + print("=" * 20) + print("Query text: {}".format(response.query_result.query_text)) + print( + "Detected intent: {} (confidence: {})\n".format( + response.query_result.intent.display_name, + response.query_result.intent_detection_confidence, + ) + ) + print("Fulfillment text: {}\n".format(response.query_result.fulfillment_text)) + + +# [END dialogflow_es_detect_intent_text] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument( + "--session-id", + help="Identifier of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument("texts", nargs="+", type=str, help="Text inputs.") + + args = parser.parse_args() + + detect_intent_texts( + args.project_id, args.session_id, args.texts, args.language_code + ) diff --git a/dialogflow/detect_intent_texts_test.py b/dialogflow/detect_intent_texts_test.py new file mode 100644 index 000000000000..9de971cb6bcc --- /dev/null +++ b/dialogflow/detect_intent_texts_test.py @@ -0,0 +1,41 @@ +# Copyright 2017 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 uuid + +from detect_intent_texts import detect_intent_texts + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +SESSION_ID = "test_{}".format(uuid.uuid4()) +TEXTS = [ + "hello", + "book a meeting room", + "Mountain View", + "tomorrow", + "10 AM", + "2 hours", + "10 people", + "A", + "yes", +] + + +def test_detect_intent_texts(capsys): + detect_intent_texts(PROJECT_ID, SESSION_ID, TEXTS, "en-US") + out, _ = capsys.readouterr() + + assert "Fulfillment text: All set!" in out diff --git a/dialogflow/detect_intent_texts_with_location.py b/dialogflow/detect_intent_texts_with_location.py new file mode 100644 index 000000000000..d52ac178dd70 --- /dev/null +++ b/dialogflow/detect_intent_texts_with_location.py @@ -0,0 +1,97 @@ +#!/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 Detect Intent Python sample to use regional endpoint. + +Examples: + python detect_intent_texts_with_location.py -h + python detect_intent_texts_with_location.py --project-id PROJECT_ID \ + --location-id LOCATION_ID --session-id SESSION_ID \ + "hello" "book a meeting room" "Mountain View" +""" + +import argparse +import uuid + + +# [START dialogflow_detect_intent_text_with_location] +def detect_intent_texts_with_location( + project_id, location_id, session_id, texts, language_code +): + """Returns the result of detect intent with texts as inputs. + + Using the same `session_id` between requests allows continuation + of the conversation.""" + from google.cloud import dialogflow + + session_client = dialogflow.SessionsClient( + client_options={"api_endpoint": f"{location_id}-dialogflow.googleapis.com"} + ) + + session = ( + f"projects/{project_id}/locations/{location_id}/agent/sessions/{session_id}" + ) + print(f"Session path: {session}\n") + + for text in texts: + text_input = dialogflow.TextInput(text=text, language_code=language_code) + + query_input = dialogflow.QueryInput(text=text_input) + + response = session_client.detect_intent( + request={"session": session, "query_input": query_input} + ) + + print("=" * 20) + print(f"Query text: {response.query_result.query_text}") + print( + f"Detected intent: {response.query_result.intent.display_name} (confidence: {response.query_result.intent_detection_confidence,})\n" + ) + print(f"Fulfillment text: {response.query_result.fulfillment_text}\n") + + +# [END dialogflow_detect_intent_text_with_location] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument("--location-id", help="Location id. Required.", required=True) + parser.add_argument( + "--session-id", + help="Identifier of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument("texts", nargs="+", type=str, help="Text inputs.") + + args = parser.parse_args() + + detect_intent_texts_with_location( + args.project_id, + args.location_id, + args.session_id, + args.texts, + args.language_code, + ) diff --git a/dialogflow/detect_intent_texts_with_location_test.py b/dialogflow/detect_intent_texts_with_location_test.py new file mode 100644 index 000000000000..64b57d88175e --- /dev/null +++ b/dialogflow/detect_intent_texts_with_location_test.py @@ -0,0 +1,44 @@ +# Copyright 2017 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 uuid + +from detect_intent_texts_with_location import detect_intent_texts_with_location + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +LOCATION_ID = "europe-west2" +SESSION_ID = "test_{}".format(uuid.uuid4()) +TEXTS = [ + "hello", + "book a meeting room", + "Mountain View", + "tomorrow", + "10 AM", + "2 hours", + "10 people", + "A", + "yes", +] + + +def test_detect_intent_texts_with_location(capsys): + detect_intent_texts_with_location( + PROJECT_ID, LOCATION_ID, SESSION_ID, TEXTS, "en-GB" + ) + out, _ = capsys.readouterr() + + assert "Fulfillment text: All set!" in out diff --git a/dialogflow/detect_intent_with_sentiment_analysis.py b/dialogflow/detect_intent_with_sentiment_analysis.py new file mode 100644 index 000000000000..c9538327e4e9 --- /dev/null +++ b/dialogflow/detect_intent_with_sentiment_analysis.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +# Copyright 2018 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 Beta Detect Intent Python sample with sentiment analysis. + +Examples: + python detect_intent_with_sentiment_analysis.py -h + python detect_intent_with_sentiment_analysis.py --project-id PROJECT_ID \ + --session-id SESSION_ID \ + "hello" "book a meeting room" "Mountain View" +""" + +import argparse +import uuid + + +# [START dialogflow_detect_intent_with_sentiment_analysis] +def detect_intent_with_sentiment_analysis(project_id, session_id, texts, language_code): + """Returns the result of detect intent with texts as inputs and analyzes the + sentiment of the query text. + + Using the same `session_id` between requests allows continuation + of the conversation.""" + from google.cloud import dialogflow + + session_client = dialogflow.SessionsClient() + + session_path = session_client.session_path(project_id, session_id) + print("Session path: {}\n".format(session_path)) + + for text in texts: + text_input = dialogflow.TextInput(text=text, language_code=language_code) + + query_input = dialogflow.QueryInput(text=text_input) + + # Enable sentiment analysis + sentiment_config = dialogflow.SentimentAnalysisRequestConfig( + analyze_query_text_sentiment=True + ) + + # Set the query parameters with sentiment analysis + query_params = dialogflow.QueryParameters( + sentiment_analysis_request_config=sentiment_config + ) + + response = session_client.detect_intent( + request={ + "session": session_path, + "query_input": query_input, + "query_params": query_params, + } + ) + + print("=" * 20) + print("Query text: {}".format(response.query_result.query_text)) + print( + "Detected intent: {} (confidence: {})\n".format( + response.query_result.intent.display_name, + response.query_result.intent_detection_confidence, + ) + ) + print("Fulfillment text: {}\n".format(response.query_result.fulfillment_text)) + # Score between -1.0 (negative sentiment) and 1.0 (positive sentiment). + print( + "Query Text Sentiment Score: {}\n".format( + response.query_result.sentiment_analysis_result.query_text_sentiment.score + ) + ) + print( + "Query Text Sentiment Magnitude: {}\n".format( + response.query_result.sentiment_analysis_result.query_text_sentiment.magnitude + ) + ) + + +# [END dialogflow_detect_intent_with_sentiment_analysis] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument( + "--session-id", + help="Identifier of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument("texts", nargs="+", type=str, help="Text inputs.") + + args = parser.parse_args() + + detect_intent_with_sentiment_analysis( + args.project_id, args.session_id, args.texts, args.language_code + ) diff --git a/dialogflow/detect_intent_with_sentiment_analysis_test.py b/dialogflow/detect_intent_with_sentiment_analysis_test.py new file mode 100644 index 000000000000..1fac5fd7ebc8 --- /dev/null +++ b/dialogflow/detect_intent_with_sentiment_analysis_test.py @@ -0,0 +1,41 @@ +# Copyright 2018 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 uuid + +from detect_intent_with_sentiment_analysis import detect_intent_with_sentiment_analysis + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +SESSION_ID = "test_{}".format(uuid.uuid4()) +TEXTS = [ + "hello", + "book a meeting room", + "Mountain View", + "tomorrow", + "10 AM", + "2 hours", + "10 people", + "A", + "yes", +] + + +def test_detect_intent_with_sentiment_analysis(capsys): + detect_intent_with_sentiment_analysis(PROJECT_ID, SESSION_ID, TEXTS, "en-US") + out, _ = capsys.readouterr() + + assert "Query Text Sentiment Score" in out diff --git a/dialogflow/detect_intent_with_texttospeech_response.py b/dialogflow/detect_intent_with_texttospeech_response.py new file mode 100644 index 000000000000..ad9ab077b021 --- /dev/null +++ b/dialogflow/detect_intent_with_texttospeech_response.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +# Copyright 2018 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 Beta Detect Intent Python sample with an audio response. + +Examples: + python detect_intent_with_texttospeech_response_test.py -h + python detect_intent_with_texttospeech_response_test.py \ + --project-id PROJECT_ID --session-id SESSION_ID "hello" +""" + +import argparse +import uuid + + +# [START dialogflow_detect_intent_with_texttospeech_response] +def detect_intent_with_texttospeech_response( + project_id, session_id, texts, language_code +): + """Returns the result of detect intent with texts as inputs and includes + the response in an audio format. + + Using the same `session_id` between requests allows continuation + of the conversation.""" + from google.cloud import dialogflow + + session_client = dialogflow.SessionsClient() + + session_path = session_client.session_path(project_id, session_id) + print("Session path: {}\n".format(session_path)) + + for text in texts: + text_input = dialogflow.TextInput(text=text, language_code=language_code) + + query_input = dialogflow.QueryInput(text=text_input) + + # Set the query parameters with sentiment analysis + output_audio_config = dialogflow.OutputAudioConfig( + audio_encoding=dialogflow.OutputAudioEncoding.OUTPUT_AUDIO_ENCODING_LINEAR_16 + ) + + request = dialogflow.DetectIntentRequest( + session=session_path, + query_input=query_input, + output_audio_config=output_audio_config, + ) + response = session_client.detect_intent(request=request) + + print("=" * 20) + print("Query text: {}".format(response.query_result.query_text)) + print( + "Detected intent: {} (confidence: {})\n".format( + response.query_result.intent.display_name, + response.query_result.intent_detection_confidence, + ) + ) + print("Fulfillment text: {}\n".format(response.query_result.fulfillment_text)) + # The response's audio_content is binary. + with open("output.wav", "wb") as out: + out.write(response.output_audio) + print('Audio content written to file "output.wav"') + + +# [END dialogflow_detect_intent_with_texttospeech_response] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + parser.add_argument( + "--session-id", + help="Identifier of the DetectIntent session. " "Defaults to a random UUID.", + default=str(uuid.uuid4()), + ) + parser.add_argument( + "--language-code", + help='Language code of the query. Defaults to "en-US".', + default="en-US", + ) + parser.add_argument("texts", nargs="+", type=str, help="Text inputs.") + + args = parser.parse_args() + + detect_intent_with_texttospeech_response( + args.project_id, args.session_id, args.texts, args.language_code + ) diff --git a/dialogflow/detect_intent_with_texttospeech_response_test.py b/dialogflow/detect_intent_with_texttospeech_response_test.py new file mode 100644 index 000000000000..1f18b9ac989b --- /dev/null +++ b/dialogflow/detect_intent_with_texttospeech_response_test.py @@ -0,0 +1,37 @@ +# Copyright 2018 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 uuid + +from detect_intent_with_texttospeech_response import ( + detect_intent_with_texttospeech_response, +) + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +SESSION_ID = "test_{}".format(uuid.uuid4()) +TEXTS = ["hello"] + + +def test_detect_intent_with_sentiment_analysis(capsys): + detect_intent_with_texttospeech_response(PROJECT_ID, SESSION_ID, TEXTS, "en-US") + out, _ = capsys.readouterr() + + assert "Audio content written to file" in out + statinfo = os.stat("output.wav") + assert statinfo.st_size > 0 + os.remove("output.wav") + assert not os.path.isfile("output.wav") diff --git a/dialogflow/document_management.py b/dialogflow/document_management.py new file mode 100644 index 000000000000..33697862edf6 --- /dev/null +++ b/dialogflow/document_management.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python + +# Copyright 2018 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 Knowledge Documents. + +Examples: + 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", + "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 +): + """Creates a Document. + + Args: + project_id: The GCP project linked with the agent. + knowledge_base_id: Id of the Knowledge base. + display_name: The display name of the Document. + mime_type: The mime_type of the Document. e.g. text/csv, text/html, + text/plain, text/pdf etc. + knowledge_type: The Knowledge type of the Document. e.g. FAQ, + EXTRACTIVE_QA. + 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 + ) + + document = dialogflow.Document( + 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...") + 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:") + for knowledge_type in document.knowledge_types: + 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) + + 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__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument("--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") + + 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_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(""), + ) + 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, + ) + create_parser.add_argument( + "--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, + ) + + 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 == "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/dialogflow/intent_management.py b/dialogflow/intent_management.py new file mode 100644 index 000000000000..30292eced7d5 --- /dev/null +++ b/dialogflow/intent_management.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python + +# Copyright 2017 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 Intent Python sample showing how to manage intents. + +Examples: + python intent_management.py -h + python intent_management.py --project-id PROJECT_ID list + python intent_management.py --project-id PROJECT_ID create \ + "room.cancellation - yes" \ + --training-phrases-parts "cancel" "cancellation" \ + --message-texts "Are you sure you want to cancel?" "Cancelled." + python intent_management.py --project-id PROJECT_ID delete \ + 74892d81-7901-496a-bb0a-c769eda5180e +""" + +import argparse + + +# [START dialogflow_list_intents] +def list_intents(project_id): + from google.cloud import dialogflow + + intents_client = dialogflow.IntentsClient() + + parent = dialogflow.AgentsClient.agent_path(project_id) + + intents = intents_client.list_intents(request={"parent": parent}) + + for intent in intents: + print("=" * 20) + print("Intent name: {}".format(intent.name)) + print("Intent display_name: {}".format(intent.display_name)) + print("Action: {}\n".format(intent.action)) + print("Root followup intent: {}".format(intent.root_followup_intent_name)) + print("Parent followup intent: {}\n".format(intent.parent_followup_intent_name)) + + print("Input contexts:") + for input_context_name in intent.input_context_names: + print("\tName: {}".format(input_context_name)) + + print("Output contexts:") + for output_context in intent.output_contexts: + print("\tName: {}".format(output_context.name)) + + +# [END dialogflow_list_intents] + + +# [START dialogflow_create_intent] +def create_intent(project_id, display_name, training_phrases_parts, message_texts): + """Create an intent of the given intent type.""" + from google.cloud import dialogflow + + intents_client = dialogflow.IntentsClient() + + parent = dialogflow.AgentsClient.agent_path(project_id) + training_phrases = [] + for training_phrases_part in training_phrases_parts: + part = dialogflow.Intent.TrainingPhrase.Part(text=training_phrases_part) + # Here we create a new training phrase for each provided part. + training_phrase = dialogflow.Intent.TrainingPhrase(parts=[part]) + training_phrases.append(training_phrase) + + text = dialogflow.Intent.Message.Text(text=message_texts) + message = dialogflow.Intent.Message(text=text) + + intent = dialogflow.Intent( + display_name=display_name, training_phrases=training_phrases, messages=[message] + ) + + response = intents_client.create_intent( + request={"parent": parent, "intent": intent} + ) + + print("Intent created: {}".format(response)) + + +# [END dialogflow_create_intent] + + +# [START dialogflow_delete_intent] +def delete_intent(project_id, intent_id): + """Delete intent with the given intent type and intent value.""" + from google.cloud import dialogflow + + intents_client = dialogflow.IntentsClient() + + intent_path = intents_client.intent_path(project_id, intent_id) + + intents_client.delete_intent(request={"name": intent_path}) + + +# [END dialogflow_delete_intent] + + +# Helper to get intent from display name. +def _get_intent_ids(project_id, display_name): + from google.cloud import dialogflow + + intents_client = dialogflow.IntentsClient() + + parent = dialogflow.AgentsClient.agent_path(project_id) + intents = intents_client.list_intents(request={"parent": parent}) + intent_names = [ + intent.name for intent in intents if intent.display_name == display_name + ] + + intent_ids = [intent_name.split("/")[-1] for intent_name in intent_names] + + return intent_ids + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + parser.add_argument( + "--project-id", help="Project/agent id. Required.", required=True + ) + + subparsers = parser.add_subparsers(dest="command") + + list_parser = subparsers.add_parser("list", help=list_intents.__doc__) + + create_parser = subparsers.add_parser("create", help=create_intent.__doc__) + create_parser.add_argument("display_name") + create_parser.add_argument( + "--training-phrases-parts", + nargs="*", + type=str, + help="Training phrases.", + default=[], + ) + create_parser.add_argument( + "--message-texts", + nargs="*", + type=str, + help="Message texts for the agent's response when the intent " "is detected.", + default=[], + ) + + delete_parser = subparsers.add_parser("delete", help=delete_intent.__doc__) + delete_parser.add_argument("intent_id", help="The id of the intent.") + + args = parser.parse_args() + + if args.command == "list": + list_intents(args.project_id) + elif args.command == "create": + create_intent( + args.project_id, + args.display_name, + args.training_phrases_parts, + args.message_texts, + ) + elif args.command == "delete": + delete_intent(args.project_id, args.intent_id) diff --git a/dialogflow/intent_management_test.py b/dialogflow/intent_management_test.py new file mode 100644 index 000000000000..0c7ed62bd672 --- /dev/null +++ b/dialogflow/intent_management_test.py @@ -0,0 +1,60 @@ +# Copyright 2017 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 uuid + +import intent_management + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +INTENT_DISPLAY_NAME = "test_{}".format(uuid.uuid4()) +MESSAGE_TEXTS = ["fake_message_text_for_testing_1", "fake_message_text_for_testing_2"] +TRAINING_PHRASE_PARTS = ["fake_training_phrase_part_1", "fake_training_phease_part_2"] + + +def test_create_intent(capsys): + intent_management.create_intent( + PROJECT_ID, INTENT_DISPLAY_NAME, TRAINING_PHRASE_PARTS, MESSAGE_TEXTS + ) + + intent_ids = intent_management._get_intent_ids(PROJECT_ID, INTENT_DISPLAY_NAME) + + assert len(intent_ids) == 1 + + intent_management.list_intents(PROJECT_ID) + + out, _ = capsys.readouterr() + + assert INTENT_DISPLAY_NAME in out + + for message_text in MESSAGE_TEXTS: + assert message_text in out + + +def test_delete_session_entity_type(capsys): + intent_ids = intent_management._get_intent_ids(PROJECT_ID, INTENT_DISPLAY_NAME) + + for intent_id in intent_ids: + intent_management.delete_intent(PROJECT_ID, intent_id) + + intent_management.list_intents(PROJECT_ID) + out, _ = capsys.readouterr() + + assert INTENT_DISPLAY_NAME not in out + + intent_ids = intent_management._get_intent_ids(PROJECT_ID, INTENT_DISPLAY_NAME) + + assert len(intent_ids) == 0 diff --git a/dialogflow/knowledge_base_management.py b/dialogflow/knowledge_base_management.py new file mode 100644 index 000000000000..5f7227d0e3b9 --- /dev/null +++ b/dialogflow/knowledge_base_management.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python + +# Copyright 2018 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 Knowledge bases. + +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 + + +# [START dialogflow_create_knowledge_base] +def create_knowledge_base(project_id, display_name): + """Creates a Knowledge base. + + Args: + 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) + + response = client.create_knowledge_base( + parent=project_path, knowledge_base=knowledge_base + ) + + print("Knowledge Base created:\n") + print("Display Name: {}\n".format(response.display_name)) + print("Name: {}\n".format(response.name)) + + +# [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(" - Name: {}".format(response.name)) + return response + + +# [END dialogflow_get_knowledge_base] + + +# [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) + + 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.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(""), + ) + + 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": + 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/dialogflow/noxfile_config.py b/dialogflow/noxfile_config.py new file mode 100644 index 000000000000..4a4db8c2de30 --- /dev/null +++ b/dialogflow/noxfile_config.py @@ -0,0 +1,38 @@ +# 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. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be inported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": False, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + # "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + "gcloud_project_env": "BUILD_SPECIFIC_GCLOUD_PROJECT", + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} diff --git a/dialogflow/participant_management.py b/dialogflow/participant_management.py new file mode 100644 index 000000000000..e2bf6169f433 --- /dev/null +++ b/dialogflow/participant_management.py @@ -0,0 +1,177 @@ +#!/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}, timeout=600 + ) + 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] + +# [START dialogflow_analyze_content_audio_stream] +def analyze_content_audio_stream( + project_id, conversation_id, participant_id, audio_file_path +): + """Analyze audio content for END_USER + + Args: + project_id: The GCP project linked with the conversation profile. + conversation_id: Id of the conversation. + participant_id: Id of the participant. + audio_file_path: audio file in wav/mp3 format contains utterances of END_USER.""" + + # Initialize client that will be used to send requests across threads. This + # client only needs to be created once, and can be reused for multiple requests. + # After completing all of your requests, call the "__exit__()" method to safely + # clean up any remaining background resources. Alternatively, use the client as + # a context manager. + client = dialogflow.ParticipantsClient() + + participant_path = client.participant_path( + project_id, conversation_id, participant_id + ) + # Note: hard coding audio_encoding and sample_rate_hertz for simplicity. + audio_encoding = dialogflow.AudioEncoding.AUDIO_ENCODING_LINEAR_16 + sample_rate_hertz = 16000 + + # Generates requests based on the audio files. Will by default use the first channel as + # END_USER, and second channel as HUMAN_AGENT. + def request_generator(audio_config, audio_file_path): + + # The first request contains the configuration. + yield dialogflow.StreamingAnalyzeContentRequest( + participant=participant_path, audio_config=audio_config + ) + + # Here we are reading small chunks of audio data from a local + # audio file. In practice these chunks should come from + # an audio input device. + with open(audio_file_path, "rb") as audio_file: + while True: + chunk = audio_file.read(4096) + if not chunk: + break + # The later requests contains audio data. + yield dialogflow.StreamingAnalyzeContentRequest(input_audio=chunk) + + audio_config = dialogflow.InputAudioConfig( + audio_encoding=audio_encoding, + language_code="en-US", + sample_rate_hertz=sample_rate_hertz, + single_utterance=True, + model="phone_call", + # Make sure your project is Dialogflow ES ENTERPRISE_TIER in order to "USE_ENHANCED" model. + model_variant="USE_ENHANCED", + ) + requests = request_generator(audio_config, audio_file_path) + responses = client.streaming_analyze_content(requests=requests) + print("=" * 20) + for response in responses: + print(f'Transcript: "{response.message.content}".') + + print("=" * 20) + + +# [END dialogflow_analyze_content_audio_stream] diff --git a/dialogflow/participant_management_test.py b/dialogflow/participant_management_test.py new file mode 100644 index 000000000000..6e4fd7e78f1e --- /dev/null +++ b/dialogflow/participant_management_test.py @@ -0,0 +1,154 @@ +# 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://cloud-samples-data/dialogflow/participant_test.html + # via Pantheon for service account (google application credential account) from here: + # https://support.google.com/googleshopping/answer/9116497 + document_management.create_document( + PROJECT_ID, + knowledge_base_id, + DOCUMENT_DISPLAY_NAME, + "text/html", + "ARTICLE_SUGGESTION", + "gs://cloud-samples-data/dialogflow/participant_test.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/dialogflow/requirements-test.txt b/dialogflow/requirements-test.txt new file mode 100644 index 000000000000..939968fd3704 --- /dev/null +++ b/dialogflow/requirements-test.txt @@ -0,0 +1,2 @@ +pytest==7.2.1 +flaky==3.7.0 diff --git a/dialogflow/requirements.txt b/dialogflow/requirements.txt new file mode 100644 index 000000000000..d2a43254ce59 --- /dev/null +++ b/dialogflow/requirements.txt @@ -0,0 +1,2 @@ +google-cloud-dialogflow==2.19.1 +Flask==2.2.2 diff --git a/dialogflow/resources/230pm.wav b/dialogflow/resources/230pm.wav new file mode 100644 index 000000000000..7509eca784dc Binary files /dev/null and b/dialogflow/resources/230pm.wav differ diff --git a/dialogflow/resources/RoomReservation.zip b/dialogflow/resources/RoomReservation.zip new file mode 100644 index 000000000000..7873fb628c89 Binary files /dev/null and b/dialogflow/resources/RoomReservation.zip differ diff --git a/dialogflow/resources/book_a_room.wav b/dialogflow/resources/book_a_room.wav new file mode 100644 index 000000000000..9124e9279460 Binary files /dev/null and b/dialogflow/resources/book_a_room.wav differ diff --git a/dialogflow/resources/half_an_hour.wav b/dialogflow/resources/half_an_hour.wav new file mode 100644 index 000000000000..71010a871bbb Binary files /dev/null and b/dialogflow/resources/half_an_hour.wav differ diff --git a/dialogflow/resources/mountain_view.wav b/dialogflow/resources/mountain_view.wav new file mode 100644 index 000000000000..1c5437f7cb5b Binary files /dev/null and b/dialogflow/resources/mountain_view.wav differ diff --git a/dialogflow/resources/today.wav b/dialogflow/resources/today.wav new file mode 100644 index 000000000000..d47ed78b3516 Binary files /dev/null and b/dialogflow/resources/today.wav differ diff --git a/dialogflow/resources/two_people.wav b/dialogflow/resources/two_people.wav new file mode 100644 index 000000000000..5114ebbd3105 Binary files /dev/null and b/dialogflow/resources/two_people.wav differ diff --git a/dialogflow/set_agent.py b/dialogflow/set_agent.py new file mode 100644 index 000000000000..c252a131a000 --- /dev/null +++ b/dialogflow/set_agent.py @@ -0,0 +1,38 @@ +# 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 +# +# https://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. + +# [START dialogflow_set_agent_sample] + +from google.cloud.dialogflow_v2 import Agent, AgentsClient + + +def set_agent(project_id, display_name): + + agents_client = AgentsClient() + + parent = agents_client.common_project_path(project_id) + + agent = Agent( + parent=parent, + display_name=display_name, + default_language_code="en", + time_zone="America/Los_Angeles", + ) + + response = agents_client.set_agent(request={"agent": agent}) + + return response + + +# [END dialogflow_set_agent_sample] diff --git a/dialogflow/set_agent_test.py b/dialogflow/set_agent_test.py new file mode 100644 index 000000000000..aff0dcdf2a70 --- /dev/null +++ b/dialogflow/set_agent_test.py @@ -0,0 +1,30 @@ +# 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 + +from google.api_core.exceptions import InvalidArgument +import pytest + +from set_agent import set_agent + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") + + +# We cannot test setAgent because Dialogflow ES can only have one agent +# and if we create a agent it will delete the exisitng testing agent and +# would cause all tests to fail +def test_set_agent(): + with pytest.raises(InvalidArgument): + set_agent(PROJECT_ID, "") diff --git a/dialogflow/update_intent.py b/dialogflow/update_intent.py new file mode 100644 index 000000000000..796ce8d1a1b2 --- /dev/null +++ b/dialogflow/update_intent.py @@ -0,0 +1,33 @@ +# 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. + +# [START dialogflow_es_update_intent] + +from google.cloud.dialogflow_v2 import IntentsClient +from google.protobuf import field_mask_pb2 + + +def update_intent(project_id, intent_id, display_name): + intents_client = IntentsClient() + + intent_name = intents_client.intent_path(project_id, intent_id) + intent = intents_client.get_intent(request={"name": intent_name}) + + intent.display_name = display_name + update_mask = field_mask_pb2.FieldMask(paths=["display_name"]) + response = intents_client.update_intent(intent=intent, update_mask=update_mask) + return response + + +# [END dialogflow_es_update_intent] diff --git a/dialogflow/update_intent_test.py b/dialogflow/update_intent_test.py new file mode 100644 index 000000000000..f28f4b304aec --- /dev/null +++ b/dialogflow/update_intent_test.py @@ -0,0 +1,60 @@ +# 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 uuid + +from google.cloud.dialogflow_v2.services.agents.client import AgentsClient +from google.cloud.dialogflow_v2.services.intents.client import IntentsClient +from google.cloud.dialogflow_v2.types.intent import Intent +import pytest + +from update_intent import update_intent + +PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT") +pytest.INTENT_ID = None + + +def create_intent(project_id): + intents_client = IntentsClient() + + parent = AgentsClient.agent_path(project_id) + + intent = Intent() + + intent.display_name = "fake_intent" + + intents = intents_client.create_intent(request={"parent": parent, "intent": intent}) + + return intents.name.split("/")[4] + + +@pytest.fixture(scope="function", autouse=True) +def setup_teardown(): + pytest.INTENT_ID = create_intent(project_id=PROJECT_ID) + print("Created Intent in setUp") + + +def test_update_intent(): + + fake_intent = "fake_intent_{}".format(uuid.uuid4()) + + actualResponse = update_intent(PROJECT_ID, pytest.INTENT_ID, fake_intent) + expectedResponse = fake_intent + + intents_client = IntentsClient() + + intents_client.delete_intent(name=actualResponse.name) + + assert actualResponse.display_name == expectedResponse diff --git a/dialogflow/webhook.py b/dialogflow/webhook.py new file mode 100644 index 000000000000..4edb2d6aea29 --- /dev/null +++ b/dialogflow/webhook.py @@ -0,0 +1,42 @@ +# 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. + +# returns fullfillment response for dialogflow detect_intent call + +# [START dialogflow_webhook] + +# TODO: change the default Entry Point text to handleWebhook + + +def handleWebhook(request): + + req = request.get_json() + + responseText = "" + intent = req["queryResult"]["intent"]["displayName"] + + if intent == "Default Welcome Intent": + responseText = "Hello from a GCF Webhook" + elif intent == "get-agent-name": + responseText = "My name is Flowhook" + else: + responseText = f"There are no fulfillment responses defined for Intent {intent}" + + # You can also use the google.cloud.dialogflowcx_v3.types.WebhookRequest protos instead of manually writing the json object + res = {"fulfillmentMessages": [{"text": {"text": [responseText]}}]} + + return res + + +# [END dialogflow_webhook] diff --git a/dialogflow/webhook_test.py b/dialogflow/webhook_test.py new file mode 100644 index 000000000000..dc8bbc58f251 --- /dev/null +++ b/dialogflow/webhook_test.py @@ -0,0 +1,41 @@ +# 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 flask +import pytest + +from webhook import handleWebhook + +# Create a fake 'app' for generating test request contexts. + +request = { + "queryResult": { + "queryText": "hi", + "intent": { + "name": "projects/galstarter-316823/agent/intents/00c2877d-2440-447f-8dc1-045623a55bd4", + "displayName": "Default Welcome Intent", + }, + } +} + + +@pytest.fixture(scope="module") +def app(): + return flask.Flask(__name__) + + +def test_handleWebhook(app): + with app.test_request_context(json=request): + res = handleWebhook(flask.request) + assert "Hello from a GCF Webhook" in str(res)