tgallice / wit-php

Wit.ai php sdk
MIT License
68 stars 16 forks source link

Get bot message #15

Closed christophrumpel closed 8 years ago

christophrumpel commented 8 years ago

Hey,

thx for the php sdk. I have setup a story on wit.ai and now I'm trying to get the bot's answer back to the user.

$response = $this->witAIClient->get('/message', [
     'q' => $message,
 ]);

I do get back some informations but not the message the bot should response / answer.

{"msg_id":"e657f02a-0d1f-442c-93f5-3cf58238d4f9","_text":"lets play word game","entities":{"my_method":[{"confidence":1,"type":"value","value":"method-type"}]}}

Is this method not meant to get the message back as well?

Thx and greets Christoph

hfinck commented 8 years ago

With the /messageendpoint you get back the entities which where extracted from the message, but not an actual action suggestion. Have a look at the converse API on wit.ai and it's representation within wit-php. For that to work you have to use Conversationand an ActionMapping. These are supposed to work together with stories defined in your bot model on wit. The converse API both extracts entities and delivers feedback on which action to execute next. E.g say in your case.

Please make sure to use the latest master version of wit-php, since there was a bug with the converse implementation and the git tag has not been bumped yet.

christophrumpel commented 8 years ago

Hey, thx a lot. I will try that!

christophrumpel commented 8 years ago

Hey, I tried it like this:

$api = new ConverseApi($this->witAIClient);
$actionMapping = new WitAIActionMapping();
$conversation = new Conversation($api, $actionMapping);

$context = $conversation->converse('session_id', $message);

$this->log->info('Debug: ', (array)$context);

What I get back as $context is this:

[2016-08-10 13:46:45] general.INFO: Debug:  {"\u0000Tgallice\\Wit\\Model\\Context\u0000data":{"reference_date":"2016-08-10T13:46:43+0200"}} []

I expected to get a string back, like I would when I test the message inside the wit.ai chat console.

The session ID is a string that I define myself to let wit.ai know if this message is from the same user right?

tgallice commented 8 years ago

Hello @christophrumpel ! Can you provide your WitAIActionMapping implementation ? If you want to catch text messages you should configure the ActionMapping::say() method to do that e.g :

class WitAIActionMapping extends ActionMapping {
    private $logger;

    public function __construct($logger) {
        $this->logger = $logger;
    }

...

    public function say($sessionId, $message, Context $context, array $entities = []) {
        // $message is the plain text message from wit.ai
        $this->logger->info($message);
    }

...
}
tgallice commented 8 years ago

The context returned from Conversation::converse is the last context at the end of the story (when wit.ai return a stop action).

The session_id is for a conversation session. From the doc:

The session_id is a unique ID you generate on your side to group messages from the same user request/conversation.
When you start a new conversation, you should generate a new one. You should generate a new one, even when the user is the same.
hfinck commented 8 years ago

You get back the context from the last converse step (which is always from the stop implementation in your action mapping).

Let me walk you through what happens exactly. The wit.ai chat console does hide quite a bit. Basically all the relevant stuff happens within the /converse call, which recursively calls itself (and the wit.ai /converse endpoint) to execute the relevant actions within your action mapping.

The message is sent to wit.ai's converse endpoint

$conversation->converse('session_id', $message)

The result of this will be mapped to a Step object, which determines what to execute within your action mapping. This is what a response from wit might look like.

{
    "type": "msg",
    "msg": "It's gonna be sunny in Brussels.",
    "confidence": 0.9963
}

Type msg means that the say action within your action mapping will called with the message string provided by wit.ai

It is up to you how you implement the say action. In my case I use Facebook's Messenger Send API to create a message and send it. Also the say action should return the (maybe modified) context.

Converse is then recursively called with that Context. Depending on your stories you might get back the following.

  {
    "type": "stop",
    "confidence": 0.9963
  }

Your actions mapping's stop method will be called and the outer call will return the Context from that stop method. All the magic already happened within that $conversation->converse call. Take the time and step through this and you will see that the methods follows the conversation flow described in the wit.ai docs.

hfinck commented 8 years ago

@christophrumpel Also yes, the session_id should identify the conversation with a user. But note if one conversation flow has ended the session_id should change. Even if the user is the same.

hfinck commented 8 years ago

@tgallice Two are better than one :-) I think now @christophrumpel has all the information he needs 👍

christophrumpel commented 8 years ago

Hey, thx yes here it is:

<?php

namespace App;

use Tgallice\Wit\ActionMapping;
use Tgallice\Wit\Model\Context;

class WitAIActionMapping extends ActionMapping
{
    /**
     * @inheritdoc
     */
    public function action($sessionId, $actionName, Context $context)
    {
        return call_user_func_array(array($this, $actionName), array($sessionId, $context));
    }

    /**
     * @inheritdoc
     */
    public function say($sessionId, $message, Context $context)
    {
        echo $message;
    }

    public function stop($sessionId, Context $context) {
        // TODO: Implement stop() method.
    }

    public function error($sessionId, Context $context, $error = 'Unknown Error', array $stepData = []) {
        // TODO: Implement error() method.
    }

    public function merge($sessionId, Context $context, array $entities) {
        // TODO: Implement merge() method.
    }

}
tgallice commented 8 years ago

@hfinck no worries, yours is well more detailed than mine :) @hfinck And with this implementation nothing was displayed ?

christophrumpel commented 8 years ago

Sorry didn't see the other messages. Will go through all of that. Thx a lot!

hfinck commented 8 years ago

@christophrumpel Little side note. You should return the context from every method. Even if you have not changed it. This becomes quite important if you implement custom actions in your mapping which probably will be modifying the context. Depending on the context keys wit.ai predicts the next actions.

christophrumpel commented 8 years ago

Thx @hfinck and @tgallice . I guess it is more clear to me. So when I send the user's message to the converse endpoint like

$context = $conversation->converse('session_id', $message);
$this->log->info('Debug Context: ', (array)$context);

Then I should get back something like that:

{
    "type": "msg",
    "msg": "It's gonna be sunny in Brussels.",
    "confidence": 0.9963
}

and because of the msg attribute the say method of my action wrapper should be called automatically, correct?

So what I see in my log is this.

[2016-08-10 16:08:00] general.INFO: Debug Context:  {"\u0000Tgallice\\Wit\\Model\\Context\u0000data":{"reference_date":"2016-08-10T16:07:59+0200"}} []

So I do get a context object back without any msg and my say method is not called. I got a log there to check that but it is not triggered.

christophrumpel commented 8 years ago

Sorry I do get the log entry from the say method, I was wrong with that. So it gets in there, but there is no message.

christophrumpel commented 8 years ago

Ah I had a bug. I now get the message inside the say method! Yes!=)

But why does my context object not look like that? Still something wrong somewhere?

{
    "type": "msg",
    "msg": "It's gonna be sunny in Brussels.",
    "confidence": 0.9963
}
hfinck commented 8 years ago
{
    "type": "msg",
    "msg": "It's gonna be sunny in Brussels.",
    "confidence": 0.9963
}

It's not what you get back at the end. This JSON is returned from wit.ai within the ::converse method and is used to decide which action to call from your action mapping.

and because of the msg attribute the say method of my action wrapper should be called automatically, correct?

It is because of the type attribute with the value msg.

You use echo within your say method, right? That is writing to php://output. Where did you intend your message should go?

tgallice commented 8 years ago

@christophrumpel I have tried a basic wit.ia story. There are a lot strange behavior with there api... Sometime it's work, sometime no... The wit api is not "pure", you can have different results for the same input. It's depend on the training of your model (story). It's can be annoyng for this kind of test.

christophrumpel commented 8 years ago

Ah ok this json is not what I get out, its just what the code is getting back from the converse call, I see!

I did log the $msg within the say method, this is how I check that. But now I get the messages :-) 👍 Thx a lot

thx @tgallice for mentioning the different outputs, I will keep that in mind when I ran in other problems. I have built a chatbot php boilerplate and I want to provide wit.ai as an option too. (https://github.com/christophrumpel/chatbot-php-boilerplate)

hfinck commented 8 years ago

@tgallice Wit has increased their initial overfitting with the stories. So if you stick to the messages a 100% the result should be reproducible. But that's only good for testing ^^

tgallice commented 8 years ago

@hfinck Yes you right for the improvement. But I can assure you, you don't get a 100% :). @christophrumpel I have released a new version of the lib 0.3.1. You will need to update your ActionMappingclass since there is a BC break, but it's include an improvement for the Conversation class (thx @hfinck ).

hfinck commented 8 years ago

@tgallice I mean if you send the exact message as in the story :) I also noticed that the reference_date in the context (which now is just useless payload) does confuse the model sometimes. It will get better once we replace it with reference_time/timezone.

christophrumpel commented 8 years ago

thx I will try that new version @tgallice