1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Tgallice\Wit; |
4
|
|
|
|
5
|
|
|
use Tgallice\Wit\Exception\BadResponseException; |
6
|
|
|
use Tgallice\Wit\Exception\ConversationException; |
7
|
|
|
use Tgallice\Wit\Exception\InvalidStepException; |
8
|
|
|
use Tgallice\Wit\Exception\MaxIterationException; |
9
|
|
|
use Tgallice\Wit\Model\Context; |
10
|
|
|
use Tgallice\Wit\Model\Step; |
11
|
|
|
use Tgallice\Wit\Model\Step\Action; |
12
|
|
|
use Tgallice\Wit\Model\Step\Merge; |
13
|
|
|
use Tgallice\Wit\Model\Step\Message; |
14
|
|
|
use Tgallice\Wit\Model\Step\Stop; |
15
|
|
|
|
16
|
|
|
class Conversation |
17
|
|
|
{ |
18
|
|
|
const MAX_STEPS_ITERATION = 5; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var ConverseApi |
22
|
|
|
*/ |
23
|
|
|
private $converseApi; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var ActionMapping |
27
|
|
|
*/ |
28
|
|
|
private $actionMapping; |
29
|
|
|
|
30
|
10 |
|
public function __construct(ConverseApi $converseApi, ActionMapping $actionMapping) |
31
|
|
|
{ |
32
|
10 |
|
$this->converseApi = $converseApi; |
33
|
10 |
|
$this->actionMapping = $actionMapping; |
34
|
10 |
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @param string $sessionId |
38
|
|
|
* @param string|null $message |
39
|
|
|
* @param Context|null $context |
40
|
|
|
* @param int $stepIteration |
41
|
|
|
* |
42
|
|
|
* @return Context The new Context |
43
|
|
|
*/ |
44
|
9 |
|
public function converse($sessionId, $message = null, Context $context = null, $stepIteration = self::MAX_STEPS_ITERATION) |
45
|
|
|
{ |
46
|
9 |
|
$context = (null !== $context) ? $context : new Context(); |
47
|
|
|
|
48
|
9 |
|
if ($stepIteration <= 0) { |
49
|
1 |
|
$error = new MaxIterationException("Max iteration exceeded"); |
50
|
1 |
|
$this->actionMapping->error($sessionId, $context, $error); |
51
|
|
|
|
52
|
1 |
|
return $context; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
try { |
56
|
9 |
|
$step = $this->getNextStep($sessionId, $message, $context); |
57
|
9 |
|
} catch (\Exception $e) { |
58
|
|
|
// Trigger the error action |
59
|
2 |
|
$stepData = $e instanceof ConversationException ? $e->getStepData() : []; |
60
|
2 |
|
$this->actionMapping->error($sessionId, $context, $e, $stepData); |
61
|
|
|
|
62
|
2 |
|
return new Context(); |
63
|
|
|
} |
64
|
|
|
|
65
|
7 |
|
return $this->performStep($sessionId, $step, $context, $stepIteration); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @param string $sessionId |
70
|
|
|
* @param string|null $message |
71
|
|
|
* @param Context $context |
72
|
|
|
* |
73
|
|
|
* @return Step Step object |
74
|
|
|
* |
75
|
|
|
* @throws BadResponseException |
76
|
|
|
* @throws ConversationException |
77
|
|
|
*/ |
78
|
9 |
|
private function getNextStep($sessionId, $message, Context $context) |
79
|
|
|
{ |
80
|
9 |
|
$stepData = $this->converseApi->converse($sessionId, $message, $context); |
81
|
|
|
|
82
|
9 |
|
if (null === $stepData) { |
83
|
1 |
|
$stepData = []; |
84
|
1 |
|
} |
85
|
|
|
|
86
|
9 |
|
if (isset($stepData['error'])) { |
87
|
1 |
|
throw new ConversationException($stepData['error'], $sessionId, $context, $stepData); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
try { |
91
|
8 |
|
$step = StepFactory::create($stepData); |
92
|
8 |
|
} catch (InvalidStepException $e) { |
93
|
1 |
|
throw new ConversationException($e->getMessage(), $sessionId, $context, $e->getStepData()); |
94
|
|
|
} |
95
|
|
|
|
96
|
7 |
|
return $step; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @param $sessionId |
101
|
|
|
* @param Step $step |
102
|
|
|
* @param Context $context |
103
|
|
|
* @param int $currentIteration |
104
|
|
|
* |
105
|
|
|
* @return Context |
106
|
|
|
*/ |
107
|
7 |
|
private function performStep($sessionId, Step $step, Context $context, $currentIteration) |
108
|
|
|
{ |
109
|
7 |
|
switch (true) { |
110
|
7 |
View Code Duplication |
case $step instanceof Merge: |
|
|
|
|
111
|
3 |
|
$newContext = $this->actionMapping->merge($sessionId, $context, $step); |
112
|
3 |
|
$context = $this->converse($sessionId, null, $newContext, --$currentIteration); |
113
|
3 |
|
break; |
114
|
6 |
View Code Duplication |
case $step instanceof Message: |
|
|
|
|
115
|
1 |
|
$this->actionMapping->say($sessionId, $context, $step); |
116
|
1 |
|
$context = $this->converse($sessionId, null, $context, --$currentIteration); |
117
|
1 |
|
break; |
118
|
6 |
View Code Duplication |
case $step instanceof Action: |
|
|
|
|
119
|
1 |
|
$newContext = $this->actionMapping->action($sessionId, $context, $step); |
120
|
1 |
|
$context = $this->converse($sessionId, null, $newContext, --$currentIteration); |
121
|
1 |
|
break; |
122
|
6 |
|
case $step instanceof Stop: |
123
|
6 |
|
$this->actionMapping->stop($sessionId, $context, $step); |
124
|
6 |
|
break; |
125
|
|
|
} |
126
|
|
|
|
127
|
7 |
|
return $context; |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.