1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
Generation.php
См. документацию.
1<?php
2declare(strict_types=1);
3
4namespace Bitrix\Landing\Copilot;
5
6use Bitrix\Landing;
7use Bitrix\Landing\Agent;
8use Bitrix\Landing\Copilot\Connector\Chat\ChatBotMessageDto;
9use Bitrix\Landing\Copilot\Generation\GenerationException;
10use Bitrix\Landing\Copilot\Generation\Scenario\IScenario;
11use Bitrix\Landing\Copilot\Generation\Scenario\Scenarist;
12use Bitrix\Landing\Copilot\Generation\Timer;
13use Bitrix\Landing\Copilot\Model\GenerationsTable;
14use Bitrix\Main\Application;
15use Bitrix\Main\ArgumentException;
16use Bitrix\Main\ORM\Query\Query;
17use Bitrix\Main\ORM\Query\Filter;
18use Bitrix\Main\Web\Json;
19
24{
25 private const EVENT_ERROR = 'onCopilotError';
26 private const EVENT_TIMER = 'onCopilotTimeIsOver';
27 private const EVENT_GENERATION_CREATE = 'onGenerationCreate';
28 private const EVENT_GENERATION_ERROR = 'onGenerationError';
29 private const EVENT_GENERATION_FINISH = 'onGenerationFinish';
30
31 private int $id;
32 private ?int $chatId = null;
33 private IScenario $scenario;
34 private Data\Site $siteData;
35 private ?array $data = null;
36 private int $step;
37 private int $authorId;
38
39 private Scenarist $scenarist;
40 private Timer $timer;
41 protected ?Generation\Event $event = null;
42
43 public function __construct()
44 {
45 $this->authorId = Landing\Manager::getUserId();
46
47 $this->siteData = new Data\Site();
48 $this->timer = new Timer();
49 }
50
55 public function getAuthorId(): int
56 {
57 return $this->authorId;
58 }
59
65 public function setChatId(int $chatId): self
66 {
67 if ($chatId > 0)
68 {
69 $this->chatId = $chatId;
70 }
71
72 return $this;
73 }
74
79 public function getChatId(): ?int
80 {
81 return $this->chatId;
82 }
83
88 public function setScenario(IScenario $scenario): self
89 {
90 $this->scenario = $scenario;
91
92 return $this;
93 }
94
98 public function getScenario(): ?IScenario
99 {
100 return $this->scenario ?? null;
101 }
102
103 public function setSiteData(Data\Site $siteData): self
104 {
105 $this->siteData = $siteData;
106
107 return $this;
108 }
109
110 public function getSiteData(): Data\Site
111 {
112 return $this->siteData;
113 }
114
120 public function getData(?string $key = null): mixed
121 {
122 if (!isset($key))
123 {
124 return $this->data;
125 }
126
127 return $this->data[$key] ?? null;
128 }
129
136 public function setData(string $key, mixed $data): void
137 {
138 if (!isset($this->data))
139 {
140 $this->data = [];
141 }
142
143 $this->data[$key] = $data;
144 }
145
151 public function deleteData(string $key): void
152 {
153 if (is_array($this->data) && array_key_exists($key, $this->data))
154 {
155 unset($this->data[$key]);
156 }
157 }
158
159 public function setWishes(Data\Wishes $wishes): self
160 {
161 $this->siteData->setWishes($wishes);
162
163 return $this;
164 }
165
166 public function getId(): ?int
167 {
168 return $this->id ?? null;
169 }
170
171 public function getStep(): ?int
172 {
173 return $this->step ?? null;
174 }
175
176 public function getTimer(): Timer
177 {
178 return $this->timer;
179 }
180
188 public function initById(int $generationId): bool
189 {
190 if ($generationId <= 0)
191 {
192 return false;
193 }
194
195 $filter =
196 Query::filter()
197 ->where('ID', '=', $generationId)
198 ;
199
200 return $this->initExists($filter);
201 }
202
210 public function initBySiteId(int $siteId, IScenario $scenario): bool
211 {
212 $filter =
213 Query::filter()
214 ->where('SCENARIO', '=', $scenario::class)
215 ->where('SITE_ID', '=', $siteId)
216 ;
217
218 return $this->initExists($filter);
219 }
220
221 private function initExists(Filter\ConditionTree $filter): bool
222 {
223 $generation = GenerationsTable::query()
224 ->where($filter)
225 ->setSelect(['ID', 'SCENARIO', 'STEP', 'CHAT_ID', 'SITE_DATA', 'DATA', 'CREATED_BY_ID'])
226 ->fetch()
227 ;
228
229 if (!$generation)
230 {
231 return false;
232 }
233
234 $this->id = (int)$generation['ID'];
235 $this->authorId = (int)$generation['CREATED_BY_ID'];
236
237 if (isset($generation['STEP']))
238 {
239 $this->step = (int)$generation['STEP'];
240 }
241
242 if (isset($generation['CHAT_ID']))
243 {
244 $this->setChatId((int)$generation['CHAT_ID']);
245 }
246
247 if (!class_exists($generation['SCENARIO']))
248 {
249 return false;
250 }
251 $this->setScenario(new ($generation['SCENARIO'])());
252
253 if (
254 isset($generation['SITE_DATA'])
255 && is_array($generation['SITE_DATA'])
256 )
257 {
258 $this->siteData = Data\Site::fromArray($generation['SITE_DATA']);
259 }
260
261 if (
262 is_array($generation['DATA'])
263 && !empty($generation['DATA'])
264 )
265 {
266 $this->data = $generation['DATA'];
267 }
268
269 if (!$this->initScenarist())
270 {
271 return false;
272 }
273
274 return true;
275 }
276
281 public function execute(): bool
282 {
283 if (!isset($this->id) && !$this->save())
284 {
285 return false;
286 }
287
288 $connection = Application::getConnection();
289 if (!$connection->lock($this->getLockName()))
290 {
291 $this->setAgent();
292
293 return false;
294 }
295
296 if (
297 !$this->isExecutable()
298 || !$this->initScenarist()
299 )
300 {
301 return false;
302 }
303
304 $this->timer->start();
305 $this->deleteAgent();
306
307 try
308 {
309 $this->scenarist
310 ->onStepChange(fn(int $newStep) => $this->step = $newStep)
311 ->onSave(fn() => $this->save())
312 ->execute()
313 ;
314
315 if ($this->scenarist->isFinished())
316 {
317 $this->onFinish();
318 }
319 }
320 catch (GenerationException $e)
321 {
322 $this->scenario->getChatbot()?->sendErrorMessage(new ChatBotMessageDto(
323 $this->getChatId() ?? 0,
324 $this->id,
325 $e->getCodeObject(),
326 $e->getParams(),
327 ));
328 $this->getEvent()->send(self::EVENT_GENERATION_ERROR);
329
330 return false;
331 }
332 catch (\RuntimeException $e)
333 {
334 $this->setAgent();
335 $this->getEvent()->send(self::EVENT_TIMER);
336
337 return false;
338 }
339 catch (\Exception $e)
340 {
341 $this->getEvent()->sendError(
342 self::EVENT_ERROR,
343 $e->getMessage(),
344 );
345
346 return false;
347 }
348
349 $connection->unlock($this->getLockName());
350
351 return true;
352 }
353
354 private function isExecutable(): bool
355 {
356 return isset(
357 $this->id,
358 $this->siteData,
359 $this->scenario,
360 );
361 }
362
363 private function getLockName(): string
364 {
365 return 'landing_copilot_generation_' . ($this->id ?? 0);
366 }
367
368 private function setAgent(): void
369 {
370 Agent::addUniqueAgent('executeGeneration', [$this->id], 60, 10);
371 }
372
373 private function deleteAgent(): void
374 {
375 Agent::deleteUniqueAgent('executeGeneration', [$this->id]);
376 }
377
382 public function finish(): void
383 {
384 if (!$this->initScenarist())
385 {
386 return;
387 }
388
389 $this->scenarist->finish();
390 $this->onFinish();
391 }
392
397 public function isFinished(): bool
398 {
399 if (!$this->initScenarist())
400 {
401 return false;
402 }
403
404 return $this->scenarist->isFinished();
405 }
406
407 private function onFinish(): void
408 {
409 $this->getEvent()->send(self::EVENT_GENERATION_FINISH);
410 }
411
416 public function isError(): bool
417 {
418 if (!$this->initScenarist())
419 {
420 return true;
421 }
422
423 return $this->scenarist->isError();
424 }
425
430 public function clearErrors(): self
431 {
432 if ($this->initScenarist())
433 {
434 $this->scenarist->clearErrors();
435 }
436
437 return $this;
438 }
439
440 private function initScenarist(): bool
441 {
442 if (!isset(
443 $this->id,
444 $this->scenario,
445 $this->siteData
446 ))
447 {
448 return false;
449 }
450
451 if (!isset($this->scenarist))
452 {
453 $this->scenarist = new Scenarist(
454 $this->scenario,
455 $this,
456 );
457 }
458
459 return true;
460 }
461
462 private function save(): bool
463 {
464 if (!isset(
465 $this->scenario,
466 $this->siteData,
467 ))
468 {
469 return false;
470 }
471
472 $fields = [
473 'SCENARIO' => $this->scenario::class,
474 'STEP' => $this->step ?? null,
475 'CHAT_ID' => $this->getChatId(),
476 'SITE_ID' => $this->siteData->getSiteId(),
477 'SITE_DATA' => $this->siteData->toArray(),
478 'DATA' => $this->getData(),
479 'CREATED_BY_ID' => $this->getAuthorId(),
480 ];
481
482 if (isset($this->id) && $this->id)
483 {
484 $res = GenerationsTable::update($this->id, $fields);
485 if ($res->isSuccess())
486 {
487 return true;
488 }
489 }
490 else
491 {
492 $res = GenerationsTable::add($fields);
493 if ($res->isSuccess())
494 {
495 $this->id = $res->getId();
496 $this->getEvent()->send(self::EVENT_GENERATION_CREATE);
497
498 return true;
499 }
500 }
501
502 return false;
503 }
504
509 public function getEvent(): Generation\Event
510 {
511 if (!$this->event)
512 {
513 $this->event = new Generation\Event($this);
514 }
515
516 if (isset($this->siteData))
517 {
518 $this->event
519 ->setSiteId($this->siteData->getSiteId())
520 ->setLandingId($this->siteData->getLandingId())
521 ;
522 }
523
524 return $this->event;
525 }
526
527 public static function checkExists(int $id): bool
528 {
529 static $generations = [];
530 if (!isset($generations[$id]))
531 {
532 $generation = GenerationsTable::query()
533 ->where('ID', '=', $id)
534 ->fetch()
535 ;
536
537 $generations[$id] = (bool)$generation;
538 }
539
540 return $generations[$id];
541 }
542
543 public function getBlocksData(array $blocks): string
544 {
545 $siteData = $this->getSiteData();
546 $imagesSet = $siteData->getImagesSet();
547
548 $blocksData = [];
549 foreach ($blocks as $block)
550 {
551 $blockData = [
552 'id' => $block->getId(),
553 'anchor' => $block->getAnchor($block->getId()),
554 'images' => $imagesSet[$block->getId()] ?? [],
555 ];
556 $blocksData[] = $blockData;
557 }
558 try
559 {
560 $blockDataEncoded = Json::encode($blocksData);
561 }
562 catch (ArgumentException $e)
563 {
564 $blockDataEncoded = '';
565 }
566
567 return $blockDataEncoded;
568 }
569}
$connection
Определения actionsdefinitions.php:38
static deleteUniqueAgent(string $funcName, array $params=[])
Определения agent.php:71
static addUniqueAgent(string $funcName, array $params=[], int $time=7200, ?int $nextExecDelay=null)
Определения agent.php:28
setSiteData(Data\Site $siteData)
Определения Generation.php:103
initBySiteId(int $siteId, IScenario $scenario)
Определения Generation.php:210
setData(string $key, mixed $data)
Определения Generation.php:136
setWishes(Data\Wishes $wishes)
Определения Generation.php:159
initById(int $generationId)
Определения Generation.php:188
setScenario(IScenario $scenario)
Определения Generation.php:88
getData(?string $key=null)
Определения Generation.php:120
setChatId(int $chatId)
Определения Generation.php:65
getBlocksData(array $blocks)
Определения Generation.php:543
deleteData(string $key)
Определения Generation.php:151
Generation Event $event
Определения Generation.php:41
static checkExists(int $id)
Определения Generation.php:527
static getUserId()
Определения manager.php:107
$fields
Определения entity.php:45
$data['IS_AVAILABLE']
Определения .description.php:13
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$filter
Определения iblock_catalog_list.php:54
$siteId
Определения ajax.php:8
Определения cookies.php:2
Определения aliases.php:105
Определения buffer.php:3
$event
Определения prolog_after.php:141
if(empty($signedUserToken)) $key
Определения quickway.php:257