1
|
|
|
<?php |
2
|
|
|
namespace Posibrain\Positron\Instinct; |
3
|
|
|
|
4
|
|
|
use Monolog\Logger; |
5
|
|
|
use Posibrain\Positron\Positron; |
6
|
|
|
use Posibrain\TchatBotConfig; |
7
|
|
|
use Posibrain\AnalysedRequest; |
8
|
|
|
use Posibrain\TchatMessage; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* |
12
|
|
|
* @author Fylhan (http://fylhan.la-bnbox.fr) |
13
|
|
|
* @license LGPL-2.1+ |
14
|
|
|
*/ |
15
|
|
|
class InstinctPositron extends Positron |
16
|
|
|
{ |
17
|
|
|
|
18
|
|
|
private static $logger = NULL; |
19
|
|
|
|
20
|
|
|
private $config; |
21
|
|
|
|
22
|
|
|
private $brainManager; |
23
|
|
|
|
24
|
|
|
private $knowledges; |
25
|
|
|
|
26
|
|
|
private $matching; |
27
|
|
|
|
28
|
|
|
public function __construct($config, $params = array()) |
29
|
|
|
{ |
30
|
|
|
// Logger |
31
|
|
View Code Duplication |
if (NULL == self::$logger) { |
|
|
|
|
32
|
|
|
self::$logger = new Logger(__CLASS__); |
33
|
|
|
if (! empty($params) && isset($params['loggerHandler'])) { |
34
|
|
|
self::$logger->pushHandler($params['loggerHandler']); |
35
|
|
|
} |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
// Brain Manager |
39
|
|
|
$this->config = $config; |
40
|
|
|
$this->brainManager = new BrainManager($params); |
41
|
|
|
|
42
|
|
|
// -- Load knowledge file |
43
|
|
|
$this->knowledges = $this->brainManager->loadBrain($this->config); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
public function isBotTriggered(TchatMessage $request, $currentAnswer = true) |
47
|
|
|
{ |
48
|
|
|
$content = $request->getMessage(); |
49
|
|
|
$triggered = (NULL != $content); |
50
|
|
|
$identity = $this->knowledges->identity; |
51
|
|
|
// Triggered by specific rules |
52
|
|
|
if (isset($identity->trigger) && ! empty($identity->trigger)) { |
53
|
|
|
// Called by his name |
54
|
|
View Code Duplication |
if (! empty($identity->trigger->called)) { |
|
|
|
|
55
|
|
|
$triggered &= preg_match('!(?:^|\s|[_-])(' . implode('|', $identity->trigger->called) . ')(?:$|\s|[\'_-])!i', $content); |
56
|
|
|
} |
57
|
|
|
// Specific sentance |
58
|
|
View Code Duplication |
if (! empty($identity->trigger->sentance)) { |
|
|
|
|
59
|
|
|
$triggered &= preg_match('!(' . implode('|', $identity->trigger->sentance) . ')!i', $content); |
60
|
|
|
} |
61
|
|
|
} |
62
|
|
|
return $triggered; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
public function generateSymbolicAnswer(AnalysedRequest $request, $memory, TchatMessage $currentAnswer = null) |
66
|
|
|
{ |
67
|
|
|
$userMessage = $request->getMessage(); |
68
|
|
|
$userName = $request->getName(); |
69
|
|
|
$dateTime = $request->getDate(); |
|
|
|
|
70
|
|
|
|
71
|
|
|
if (null == $this->knowledges) { |
72
|
|
|
return null; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$identity = $this->knowledges->identity; |
76
|
|
|
$synonyms = $this->knowledges->synonyms; |
|
|
|
|
77
|
|
|
$knowledge = $this->knowledges->keywords; |
|
|
|
|
78
|
|
|
|
79
|
|
|
// -- Generate reply |
80
|
|
|
// - Check User Message |
81
|
|
|
if (empty($userMessage)) { |
82
|
|
|
$message = 'Hello'; |
|
|
|
|
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
// - Best keyword priority |
86
|
|
|
$keywordItem = $this->findBestPriorityKeyword($userName, $userMessage); |
87
|
|
|
|
88
|
|
|
// - Best variance for this keyword |
89
|
|
|
$varianceItem = $this->findBestVariance($userName, $userMessage, $keywordItem); |
90
|
|
|
$this->matching = $varianceItem; |
91
|
|
|
$response = $this->pickResponse($userName, $userMessage, $varianceItem); |
92
|
|
|
|
93
|
|
|
// if ('UTF-8' != $this->config->getCharset()) {} |
94
|
|
|
$currentAnswer = new TchatMessage($response, $identity->name); |
95
|
|
|
return $currentAnswer; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
public function provideMeaning(AnalysedRequest $request, $memory, TchatMessage $answer, TchatMessage $currentAnswer = null) |
99
|
|
|
{ |
100
|
|
|
if (null == $currentAnswer) { |
101
|
|
|
$currentAnswer = $answer; |
102
|
|
|
} |
103
|
|
|
$message = $currentAnswer->getMessage(); |
104
|
|
|
// Post traitment |
105
|
|
|
if (strstr($message, '${time}')) { |
106
|
|
|
$nowDate = new \DateTime(null, new \DateTimeZone(! isset($this->knowledges->identity->timezone) ? 'Europe/Paris' : $this->knowledges->identity->timezone)); |
107
|
|
|
$message = preg_replace('!\$\{time\}!i', $nowDate->format('H\hi'), $message); |
108
|
|
|
} |
109
|
|
|
if (strstr($message, '${name}')) { |
110
|
|
|
$message = preg_replace('!\$\{name\}!i', $this->knowledges->identity->name, $message); |
111
|
|
|
} |
112
|
|
|
if (strstr($message, '${conceptorName}')) { |
113
|
|
|
$message = preg_replace('!\$\{conceptorName\}!i', $this->knowledges->identity->conceptorName, $message); |
114
|
|
|
} |
115
|
|
|
if (strstr($message, '${userName}')) { |
116
|
|
|
$message = preg_replace('!\$\{userName\}!i', $request->getName(), $message); |
117
|
|
|
} |
118
|
|
|
if (! empty($this->matching->matchingData) && count($this->matching->matchingData) > 0) { |
119
|
|
|
foreach ($this->matching->matchingData as $i => $data) { |
120
|
|
|
$data = mb_strtolower($data[0]); |
121
|
|
|
$message = preg_replace('!\$\{' . $i . '\}!i', $data, $message); |
122
|
|
|
$message = preg_replace('!\$\{' . $i . '\|clean\}!i', parserUrl($data), $message); |
123
|
|
|
$message = preg_replace('!\$\{' . $i . '\|ucfirst\}!i', ucfirst($data), $message); |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
if (! empty($this->matching->matchingKeyword) && count($this->matching->matchingKeyword) > 0) { |
127
|
|
|
$data = mb_strtolower($this->matching->matchingKeyword[0]); |
128
|
|
|
$message = preg_replace('!\$\{keyword\}!i', $data, $message); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$currentAnswer->setMessage($message); |
132
|
|
|
return $currentAnswer; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
public function beautifyAnswer(AnalysedRequest $request, $memory, TchatMessage $answer, TchatMessage $currentAnswer = null) |
136
|
|
|
{ |
137
|
|
|
if (null == $currentAnswer) { |
138
|
|
|
$currentAnswer = $answer; |
139
|
|
|
} |
140
|
|
|
$currentAnswer->setMessage(preg_replace('!(bonjour)!i', '<strong>$1</strong>', ucfirst($currentAnswer->getMessage()))); |
141
|
|
|
return $currentAnswer; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
private function findBestPriorityKeyword($userName, $message) |
|
|
|
|
145
|
|
|
{ |
146
|
|
|
$bestPriority = - 1; |
147
|
|
|
$matchingKeywordItem = ''; |
148
|
|
|
// Loop over keywords |
149
|
|
|
foreach ($this->knowledges->keywords as $keywordItem) { |
150
|
|
|
// Better priority and matching keyword (or it is the default one) |
151
|
|
|
if ($keywordItem->priority > $bestPriority && (empty($keywordItem->keyword) || preg_match('!(?:^|\s|[_-])(' . implode('|', $keywordItem->keyword) . ')(?:$|\s|[\'_,;:-])!i', $message, $matching))) { |
152
|
|
|
$bestPriority = $keywordItem->priority; |
153
|
|
|
$matchingKeywordItem = $keywordItem; |
154
|
|
|
if (! empty($matching)) { |
155
|
|
|
array_shift($matching); |
156
|
|
|
$matchingKeywordItem->matchingKeyword = $matching; |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
return $matchingKeywordItem; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
private function findBestVariance($userName, $message, $keyword) |
|
|
|
|
164
|
|
|
{ |
165
|
|
|
// Verify |
166
|
|
|
if (empty($keyword)) { |
167
|
|
|
self::$logger->addError('Hum, this keyword item is kind of empty', $keyword); |
168
|
|
|
return; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
$bestPriority = - 1; |
172
|
|
|
$matchingVarianceItem; |
|
|
|
|
173
|
|
|
// Search best variance |
174
|
|
|
if (! empty($keyword->variances)) { |
175
|
|
|
foreach ($keyword->variances as $varianceItem) { |
176
|
|
|
$varianceSize = strlen($varianceItem->variance); |
177
|
|
|
if ($varianceSize > $bestPriority && preg_match_all('!' . $varianceItem->varianceRegexable . '!is', $message, $matching)) { |
178
|
|
|
$bestPriority = $varianceSize; |
179
|
|
|
$matchingVarianceItem = $varianceItem; |
180
|
|
|
if (! empty($matching)) { |
181
|
|
|
array_shift($matching); |
182
|
|
|
$matchingVarianceItem->matchingData = $matching; |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
// No variance found? Use default responses |
188
|
|
|
if (empty($matchingVarianceItem->responses)) { |
189
|
|
|
@$matchingVarianceItem->responses = $keyword->defaultResponses; |
|
|
|
|
190
|
|
|
} |
191
|
|
|
$matchingVarianceItem->matchingKeyword = @$keyword->matchingKeyword; |
192
|
|
|
return $matchingVarianceItem; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
private function pickResponse($userName, $userMessage, $varianceItem) |
|
|
|
|
196
|
|
|
{ |
197
|
|
|
// Verify |
198
|
|
|
if (empty($varianceItem->responses)) { |
199
|
|
|
return 'Ouch !'; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
// Select random response |
203
|
|
|
$index = mt_rand(0, count($varianceItem->responses) - 1); |
204
|
|
|
$response = $varianceItem->responses[$index]; |
205
|
|
|
return $response; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
public function getKnowledges() |
209
|
|
|
{ |
210
|
|
|
return $this->knowledges; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
public function setKnowledges($knowledges) |
214
|
|
|
{ |
215
|
|
|
$this->knowledges = $knowledges; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
public function getConfig() |
219
|
|
|
{ |
220
|
|
|
return $this->config; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
public function setConfig($config) |
224
|
|
|
{ |
225
|
|
|
$this->config = $config; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
public function setBrainManager($brainManager) |
229
|
|
|
{ |
230
|
|
|
$this->brainManager = $brainManager; |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
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.