async def create_conversation(self, reference: ConversationReference, logic: Callable[[TurnContext], Awaitable]=None): """ Starts a new conversation with a user. This is typically used to Direct Message (DM) a member of a group. :param reference: :param logic: :return: """ try: if reference.service_url is None: raise TypeError('BotFrameworkAdapter.create_conversation(): reference.service_url cannot be None.') # Create conversation parameters = ConversationParameters(bot=reference.bot) client = self.create_connector_client(reference.service_url) # Mix in the tenant ID if specified. This is required for MS Teams. if reference.conversation is not None and reference.conversation.tenant_id: # Putting tenant_id in channel_data is a temporary while we wait for the Teams API to be updated parameters.channel_data = {'tenant': {'id': reference.conversation.tenant_id}} # Permanent solution is to put tenant_id in parameters.tenant_id parameters.tenant_id = reference.conversation.tenant_id resource_response = await client.conversations.create_conversation(parameters) request = TurnContext.apply_conversation_reference(Activity(), reference, is_incoming=True) request.conversation = ConversationAccount(id=resource_response.id) if resource_response.service_url: request.service_url = resource_response.service_url context = self.create_context(request) return await self.run_pipeline(context, logic) except Exception as e: raise e
def test_conversations_create_conversation(self): test_object = ChannelAccount(id=RECIPIENT_ID) create_conversation = ConversationParameters( bot=ChannelAccount(id=BOT_ID), members=[test_object], activity=Activity( type=ActivityTypes.message, channel_id=CHANNEL_ID, from_property=ChannelAccount(id=BOT_ID), recipient=test_object, text="Hi there!", ), ) # creds = MicrosoftTokenAuthenticationStub(get_auth_token()) print("Printing the pointer to the generated MicrosoftAppCredentials:") # print(creds) connector = ConnectorClient(self.credentials, base_url=SERVICE_URL) try: conversation = self.loop.run_until_complete( connector.conversations.create_conversation( create_conversation)) except Exception as error: raise error else: assert conversation.id is not None
async def send(self, message: Message): """Send a message.""" if isinstance(message.target, str): teams_channel_id = self.parse_channel_id(message.target) try: connector_client = await self.adapter.create_connector_client( self.service_endpoints[teams_channel_id]) await connector_client.conversations.create_conversation( ConversationParameters( is_group=True, channel_data={"channel": { "id": teams_channel_id }}, activity=MessageFactory.text(message.text), )) except KeyError: _LOGGER.error( "Unable to send a message until someone has spoken to the bot first." ) elif isinstance(message.target, ConversationReference): await self.adapter.continue_conversation( message.target, lambda turn_context: turn_context.send_activity(message.text), self.app_id, ) else: _LOGGER.error( f"'{message.target}' is not a valid place to send a message.")
async def create_conversation(self, reference: ConversationReference, logic): """ Starts a new conversation with a user. This is typically used to Direct Message (DM) a member of a group. :param reference: :param logic: :return: """ try: if reference.service_url is None: raise TypeError( 'BotFrameworkAdapter.create_conversation(): reference.service_url cannot be None.' ) # Create conversation parameters = ConversationParameters(bot=reference.bot) client = self.create_connector_client(reference.service_url) resource_response = await client.conversations.create_conversation( parameters) request = TurnContext.apply_conversation_reference( Activity(), reference, is_incoming=True) request.conversation = ConversationAccount(id=resource_response.id) if resource_response.service_url: request.service_url = resource_response.service_url context = self.create_context(request) return await self.run_middleware(context, logic) except Exception as e: raise e
async def send_execsum(req: Request) -> Response: try: credentials = MicrosoftAppCredentials(CONFIG.APP_ID, CONFIG.APP_PASSWORD) client = ConnectorClient(credentials, 'https://smba.trafficmanager.net/fr/') teams_client = TeamsConnectorClient(credentials, 'https://smba.trafficmanager.net/fr/') teams_channels = teams_client.teams.get_teams_channels('19:[email protected]') general_channel = next(channel for channel in teams_channels.conversations if channel.name is None) conversation_parameters = ConversationParameters( is_group=True, channel_data={"channel": {"id": general_channel.id}}, activity=MessageFactory.attachment( CardFactory.adaptive_card({ "type": "AdaptiveCard", "version": "1.0", "body": [ { "type": "TextBlock", "text": "[email protected] sent an execsum", }, ], "actions": [ { "type": "Action.OpenUrl", "title": "View execsum", "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" } ] }) ), ) client.conversations.create_conversation(conversation_parameters) return Response(status=HTTPStatus.OK) except Exception: traceback.print_exc()
async def _send_proactive_non_threaded_message(self, turn_context: TurnContext): conversation_reference = TurnContext.get_conversation_reference( turn_context.activity) conversation_parameters = ConversationParameters( is_group=False, bot=turn_context.activity.recipient, members=[turn_context.activity.from_property], tenant_id=turn_context.activity.conversation.tenant_id, ) proactive_message = MessageFactory.text("This is a proactive message") proactive_message.label = turn_context.activity.id async def get_ref(tc1): conversation_reference_inner = TurnContext.get_conversation_reference( tc1.activity) return await tc1.adapter.continue_conversation( conversation_reference_inner, send_message, self._app_id) async def send_message(tc2: TurnContext): return await tc2.send_activity(proactive_message) await turn_context.adapter.create_conversation( conversation_reference, get_ref, conversation_parameters)
async def send_private_message(turn_context: TurnContext, user_id: str, activity: Activity): """ Send proactive message to the user (Does not broke the chat conversation) """ conversation_reference = TurnContext.get_conversation_reference( turn_context.activity ) conversation_parameters = ConversationParameters( is_group=False, bot=turn_context.activity.recipient, members=[await TeamsInfo.get_member(turn_context, user_id)], tenant_id=turn_context.activity.conversation.tenant_id, ) async def get_reference(temp_turn_context_1: TurnContext): conversation_reference_inner = TurnContext.get_conversation_reference( temp_turn_context_1.activity ) return await temp_turn_context_1.adapter.continue_conversation( conversation_reference_inner, send_message, temp_turn_context_1.adapter.settings.app_id ) async def send_message(temp_turn_context_2: TurnContext): return await temp_turn_context_2.send_activity(activity) await turn_context.adapter.create_conversation( conversation_reference, get_reference, conversation_parameters )
async def _message_all_members(self, turn_context: TurnContext): team_members = await TeamsInfo.get_members(turn_context) for member in team_members: conversation_reference = TurnContext.get_conversation_reference( turn_context.activity) conversation_parameters = ConversationParameters( is_group=False, bot=turn_context.activity.recipient, members=[member], tenant_id=turn_context.activity.conversation.tenant_id, ) async def get_ref(tc1): conversation_reference_inner = TurnContext.get_conversation_reference( tc1.activity) return await tc1.adapter.continue_conversation( conversation_reference_inner, send_message, self._app_id) async def send_message(tc2: TurnContext): return await tc2.send_activity( f"Hello {member.name}. I'm a Teams conversation bot.") # pylint: disable=cell-var-from-loop await turn_context.adapter.create_conversation( conversation_reference, get_ref, conversation_parameters) await turn_context.send_activity( MessageFactory.text("All messages have been sent"))
def test_conversations_create_conversation_with_bot_as_only_member_fails( self): test_object = ChannelAccount(id=BOT_ID) sender = ChannelAccount(id=BOT_ID) create_conversation = ConversationParameters( bot=sender, members=[test_object], activity=Activity( type=ActivityTypes.message, channel_id=CHANNEL_ID, from_property=sender, recipient=test_object, text="Hi there!", ), ) with pytest.raises(ErrorResponseException) as excinfo: connector = ConnectorClient(self.credentials, base_url=SERVICE_URL) self.loop.run_until_complete( connector.conversations.create_conversation( create_conversation)) assert excinfo.value.error.error.code == "BadArgument" assert "Bots cannot IM other bots" in str( excinfo.value.error.error.message)
async def test_on_create_conversation(self): mock_adapter = Mock() sut = self.create_skill_handler_for_testing(mock_adapter) conversation_parameters = ConversationParameters() with self.assertRaises(BotActionNotImplementedError): await sut.test_on_create_conversation(self._claims_identity, conversation_parameters)
async def send_message(req: Request) -> Response: try: credentials = MicrosoftAppCredentials(CONFIG.APP_ID, CONFIG.APP_PASSWORD) client = ConnectorClient(credentials, 'https://smba.trafficmanager.net/fr/') teams_client = TeamsConnectorClient(credentials, 'https://smba.trafficmanager.net/fr/') teams_channels = teams_client.teams.get_teams_channels('19:[email protected]') general_channel = next(channel for channel in teams_channels.conversations if channel.name is None) conversation_parameters = ConversationParameters( is_group=True, channel_data={"channel": {"id": general_channel.id}}, activity=MessageFactory.content_url('https://picsum.photos/200/300', 'image/png'), ) client.conversations.create_conversation(conversation_parameters) return Response(status=HTTPStatus.OK) except Exception: traceback.print_exc()
def test_conversations_create_conversation_without_members_fails(self): create_conversation = ConversationParameters( bot=ChannelAccount(id=BOT_ID), activity=Activity( type=ActivityTypes.message, channel_id=CHANNEL_ID, from_property=ChannelAccount(id=BOT_ID), text="Hi there!", ), members=[], ) with pytest.raises(ErrorResponseException) as excinfo: connector = ConnectorClient(self.credentials, base_url=SERVICE_URL) connector.conversations.create_conversation(create_conversation) assert excinfo.value.error.error.code == "BadArgument" assert "Conversations" in str(excinfo.value.error.error.message)
def test_conversations_create_conversation(self): test_object = ChannelAccount(id=RECIPIENT_ID) create_conversation = ConversationParameters( bot=ChannelAccount(id=BOT_ID), members=[test_object], activity=Activity( type=ActivityTypes.message, channel_id=CHANNEL_ID, from_property=ChannelAccount(id=BOT_ID), recipient=test_object, text="Hi there!", ), ) connector = ConnectorClient(self.credentials, base_url=SERVICE_URL) conversation = connector.conversations.create_conversation( create_conversation) assert conversation.id is not None
async def teams_create_conversation(self, turn_context: TurnContext, teams_channel_id: str, message): params = ConversationParameters( is_group=True, channel_data={"channel": { "id": teams_channel_id }}, activity=message) connector_client = await turn_context.adapter.create_connector_client( turn_context.activity.service_url) conversation_resource_response = await connector_client.conversations.create_conversation( params) conversation_reference = TurnContext.get_conversation_reference( turn_context.activity) conversation_reference.conversation.id = conversation_resource_response.id return [ conversation_reference, conversation_resource_response.activity_id ]
def test_conversations_create_conversation_with_invalid_bot_id_fails(self): test_object = ChannelAccount(id=RECIPIENT_ID) create_conversation = ConversationParameters( bot=ChannelAccount(id="INVALID"), members=[test_object], activity=Activity( type=ActivityTypes.message, channel_id=CHANNEL_ID, from_property=ChannelAccount(id="INVALID"), recipient=test_object, text="Hi there!", ), ) with pytest.raises(ErrorResponseException) as excinfo: connector = ConnectorClient(self.credentials, base_url=SERVICE_URL) connector.conversations.create_conversation(create_conversation) assert excinfo.value.error.error.code == "ServiceError" assert "Invalid userId" in str(excinfo.value.error.error.message)
async def send_message_to_teams_channel( turn_context: TurnContext, activity: Activity, teams_channel_id: str) -> Tuple[ConversationReference, str]: if not turn_context: raise ValueError("The turn_context cannot be None") if not activity: raise ValueError("The activity cannot be None") if not teams_channel_id: raise ValueError("The teams_channel_id cannot be None or empty") old_ref = TurnContext.get_conversation_reference(turn_context.activity) conversation_parameters = ConversationParameters( is_group=True, channel_data={"channel": { "id": teams_channel_id }}, activity=activity, ) result = await turn_context.adapter.create_conversation( old_ref, TeamsInfo._create_conversation_callback, conversation_parameters) return (result[0], result[1])
async def create_conversation( self, reference: ConversationReference, logic: Callable[[TurnContext], Awaitable] = None, conversation_parameters: ConversationParameters = None, channel_id: str = None, service_url: str = None, credentials: AppCredentials = None, ): """ Starts a new conversation with a user. Used to direct message to a member of a group. :param reference: The conversation reference that contains the tenant :type reference: :class:`botbuilder.schema.ConversationReference` :param logic: The logic to use for the creation of the conversation :type logic: :class:`typing.Callable` :param conversation_parameters: The information to use to create the conversation :type conversation_parameters: :param channel_id: The ID for the channel. :type channel_id: :class:`typing.str` :param service_url: The channel's service URL endpoint. :type service_url: :class:`typing.str` :param credentials: The application credentials for the bot. :type credentials: :class:`botframework.connector.auth.AppCredentials` :raises: It raises a generic exception error. :return: A task representing the work queued to execute. .. remarks:: To start a conversation, your bot must know its account information and the user's account information on that channel. Most channels only support initiating a direct message (non-group) conversation. The adapter attempts to create a new conversation on the channel, and then sends a conversation update activity through its middleware pipeline to the the callback method. If the conversation is established with the specified users, the ID of the activity will contain the ID of the new conversation. """ try: if not service_url: service_url = reference.service_url if not service_url: raise TypeError( "BotFrameworkAdapter.create_conversation(): service_url or reference.service_url is required." ) if not channel_id: channel_id = reference.channel_id if not channel_id: raise TypeError( "BotFrameworkAdapter.create_conversation(): channel_id or reference.channel_id is required." ) parameters = (conversation_parameters if conversation_parameters else ConversationParameters(bot=reference.bot, members=[reference.user], is_group=False)) # Mix in the tenant ID if specified. This is required for MS Teams. if reference.conversation and reference.conversation.tenant_id: # Putting tenant_id in channel_data is a temporary while we wait for the Teams API to be updated parameters.channel_data = { "tenant": { "id": reference.conversation.tenant_id } } # Permanent solution is to put tenant_id in parameters.tenant_id parameters.tenant_id = reference.conversation.tenant_id # This is different from C# where credentials are required in the method call. # Doing this for compatibility. app_credentials = (credentials if credentials else await self.__get_app_credentials( self.settings.app_id, self.__get_botframework_oauth_scope())) # Create conversation client = self._get_or_create_connector_client( service_url, app_credentials) resource_response = await client.conversations.create_conversation( parameters) event_activity = Activity( type=ActivityTypes.event, name="CreateConversation", channel_id=channel_id, service_url=service_url, id=resource_response.activity_id if resource_response.activity_id else str(uuid.uuid4()), conversation=ConversationAccount( id=resource_response.id, tenant_id=parameters.tenant_id, ), channel_data=parameters.channel_data, recipient=parameters.bot, ) context = self._create_context(event_activity) context.turn_state[BotAdapter.BOT_CONNECTOR_CLIENT_KEY] = client claims_identity = ClaimsIdentity( claims={ AuthenticationConstants.AUDIENCE_CLAIM: app_credentials.microsoft_app_id, AuthenticationConstants.APP_ID_CLAIM: app_credentials.microsoft_app_id, AuthenticationConstants.SERVICE_URL_CLAIM: service_url, }, is_authenticated=True, ) context.turn_state[BotAdapter.BOT_IDENTITY_KEY] = claims_identity return await self.run_pipeline(context, logic) except Exception as error: raise error
async def create_conversation( self, reference: ConversationReference, logic: Callable[[TurnContext], Awaitable] = None, conversation_parameters: ConversationParameters = None, ): """ Starts a new conversation with a user. Used to direct message to a member of a group. :param reference: The conversation reference that contains the tenant :type reference: :class:`botbuilder.schema.ConversationReference` :param logic: The logic to use for the creation of the conversation :type logic: :class:`typing.Callable` :param conversation_parameters: The information to use to create the conversation :type conversation_parameters: :raises: It raises a generic exception error. :return: A task representing the work queued to execute. .. remarks:: To start a conversation, your bot must know its account information and the user's account information on that channel. Most channels only support initiating a direct message (non-group) conversation. The adapter attempts to create a new conversation on the channel, and then sends a conversation update activity through its middleware pipeline to the the callback method. If the conversation is established with the specified users, the ID of the activity will contain the ID of the new conversation.</para> """ try: if reference.service_url is None: raise TypeError( "BotFrameworkAdapter.create_conversation(): reference.service_url cannot be None." ) # Create conversation parameters = (conversation_parameters if conversation_parameters else ConversationParameters(bot=reference.bot, members=[reference.user], is_group=False)) client = await self.create_connector_client(reference.service_url) # Mix in the tenant ID if specified. This is required for MS Teams. if reference.conversation is not None and reference.conversation.tenant_id: # Putting tenant_id in channel_data is a temporary while we wait for the Teams API to be updated parameters.channel_data = { "tenant": { "id": reference.conversation.tenant_id } } # Permanent solution is to put tenant_id in parameters.tenant_id parameters.tenant_id = reference.conversation.tenant_id resource_response = await client.conversations.create_conversation( parameters) request = TurnContext.apply_conversation_reference( Activity(type=ActivityTypes.event, name="CreateConversation"), reference, is_incoming=True, ) request.conversation = ConversationAccount( id=resource_response.id, tenant_id=parameters.tenant_id) request.channel_data = parameters.channel_data if resource_response.service_url: request.service_url = resource_response.service_url context = self.create_context(request) return await self.run_pipeline(context, logic) except Exception as error: raise error
async def _message_all_members(self, turn_context: TurnContext, transcription_text, meeting_url, GUID): team_members = await self._get_paged_members(turn_context) for member in team_members: # check if member's name was mentioned in meeting member_first_name = member.name.split(" ")[0] if transcription_text.lower().find( member_first_name.lower()) != -1: mentioned_members_list.append(member_first_name) # split text into words. Remove punctuation to prevent mistakes in indexing transcription_text = transcription_text.replace(",", "") transcription_text = transcription_text.replace(".", "") transcription_text = transcription_text.replace("?", " ") transcription_text = transcription_text.replace("\\r", " ") transcription_text = transcription_text.replace("\\n", "") transcription_list = transcription_text.lower().split(" ") mentioned_messages_list = [] startIndex = -1 matchFound = 0 for i in range(0, len(transcription_list)): try: # find name placement in transcription list indexFound = transcription_list.index( member_first_name.lower(), startIndex + 1) except: # if name is no longer in transcription list..break loop of looking for more name mentions break # get range of words around name to get context and form message context_threshold_range = 10 context_message = "" # compose message with context for word in range(indexFound - context_threshold_range, indexFound + context_threshold_range): context_message += transcription_list[word] + " " # add mentioned message instnace into list of mentions (multiple times during a meeting) message_start_time = TranscriptionScraper.getTimeStamps( GUID, member_first_name.lower()) context_message += "... @" + message_start_time[ matchFound] + "|" matchFound = matchFound + 1 mentioned_messages_list.append(context_message) # update startIndex to start after found startIndex = indexFound conversation_reference = TurnContext.get_conversation_reference( turn_context.activity) conversation_parameters = ConversationParameters( is_group=False, bot=turn_context.activity.recipient, members=[member], tenant_id=turn_context.activity.conversation.tenant_id, ) async def get_ref(tc1): conversation_reference_inner = TurnContext.get_conversation_reference( tc1.activity) return await tc1.adapter.continue_conversation( conversation_reference_inner, send_message, self._app_id) buttons = [ CardAction(type=ActionTypes.message_back, title="See Meeting Recording", text="recording", value={"meetingURL": meeting_url}) ] mentions_text = ','.join(mentioned_messages_list) card = HeroCard( title="Hi you were mentioned in this meeting!", subtitle="See the context of the mentions below!", text=mentions_text, buttons=buttons) async def send_message(tc2: TurnContext): return await tc2.send_activity( MessageFactory.attachment(CardFactory.hero_card(card))) # pylint: disable=cell-var-from-loop await turn_context.adapter.create_conversation( conversation_reference, get_ref, conversation_parameters) mentioned_members = ','.join(mentioned_members_list) await turn_context.send_activity( MessageFactory.text( "All members who's names were mentioned in the meeting were notified with context: " + mentioned_members)) mentioned_members_list.clear()