Search code examples
pythonbotframeworkpython-asynciodirect-line-botframework

send bot framework activity from business logic Python


I'm trying the Bot Framework SDK V4 Python GA. Once I detect the intent with LUIS, I want to be able to process some business logic and respond back. I want to be able to send messages while the business logic as I want to user to know that the logic is being processed and need him to wait for a moment. I understand that bots aren't generally used for long running processes, but I've an use case where this is needed. I'm trying to pass the turncontext to the business logic and send a message from there, but it throws the following error.

can't pickle coroutine objects

Error

I'm new to async programming and not sure what's exactly happening here. Below is what I've tried. I've tried doing the same by placing the business logic in a different class altogether, but got the same issue. The initial message from on_message_activity goes well, but when trying to send the message from business, it throws the above error. What am I missing here?

async def someUseCase(self,turncontext: TurnContext):
    await turncontext.send_activity(MessageFactory.text("Processing your query. Give me a moment."))
    output = someLongRunningBusinessLogic()
    return MessageFactory.text(output)

async def on_message_activity(self, turn_context: TurnContext):
    luisResult = await self.LuisRecog.recognize(turn_context) 
    print(luisResult.get_top_scoring_intent())
    intent = LuisRecognizer.top_intent(luisResult,min_score=0.40)
    if intent != "None":
        await turn_context.send_activity("processing your query...")
        return await turn_context.send_activity(self.someUseCase(turn_context))
    else:
        await turn_context.send_activity(MessageFactory.text("No intent detected."))

Emulator Output


Solution

  • async def functions return awaitables that should be awaited. The error you encountered is likely because you were trying to pass a coroutine to a function that expected an activity on this line:

    return await turn_context.send_activity(self.someUseCase(turn_context))
    

    send_activity expects an activity but someUseCase returns a coroutine.

    You can read more about coroutines in the Python documentation: https://docs.python.org/3/library/asyncio-task.html