This repository has been archived on 2026-07-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
SmartAssistant/files/custom/Espo/Modules/SmartAssistant/Services/CaseMemoryService.php
T
chaim a148e0f99e feat: initial SmartAssistant module — unified AI assistant with case memory
Merges CrmAssistant + OfficeAssistant into a single module with:
- Floating chat (FAB) with auto office/case mode detection
- CaseMemory entity for persistent per-case knowledge
- save_memory AI tool for proactive memory saving
- Auto-extraction hooks (status changes, hearings)
- AlertCalculator for office-level alerts
- Full conversation persistence via ConversationRepository
- RTL/Hebrew support throughout (fa_IR)

47 files, 0 dependencies on old modules.
2026-03-23 14:38:49 +00:00

106 lines
3.3 KiB
PHP

<?php
namespace Espo\Modules\SmartAssistant\Services;
use Espo\ORM\EntityManager;
use Espo\ORM\Entity;
use Espo\Core\Utils\Log;
class CaseMemoryService
{
private EntityManager $entityManager;
private Log $log;
public function __construct(EntityManager $entityManager, Log $log)
{
$this->entityManager = $entityManager;
$this->log = $log;
}
public function createMemory(
string $caseId,
string $category,
string $name,
string $content,
string $importance = 'normal',
string $source = 'manual',
?string $sourceEntityType = null,
?string $sourceEntityId = null
): Entity {
$entry = $this->entityManager->getNewEntity('CaseMemory');
$entry->set([
'name' => $name,
'caseId' => $caseId,
'category' => $category,
'content' => $content,
'importance' => $importance,
'source' => $source,
'sourceEntityType' => $sourceEntityType,
'sourceEntityId' => $sourceEntityId,
]);
$this->entityManager->saveEntity($entry);
$this->log->info("SmartAssistant: Created CaseMemory id={$entry->get('id')} for case={$caseId} category={$category}");
return $entry;
}
public function getMemoriesByCase(string $caseId, ?string $category = null, bool $includeArchived = false): array
{
$where = ['caseId' => $caseId, 'deleted' => false];
if ($category) {
$where['category'] = $category;
}
if (!$includeArchived) {
$where['isArchived'] = false;
}
$entries = $this->entityManager->getRDBRepository('CaseMemory')
->where($where)
->order([['isPinned', 'DESC'], ['createdAt', 'DESC']])
->find();
$grouped = [];
foreach ($entries as $entry) {
$cat = $entry->get('category');
if (!isset($grouped[$cat])) $grouped[$cat] = [];
$grouped[$cat][] = [
'id' => $entry->get('id'),
'name' => $entry->get('name'),
'content' => $entry->get('content'),
'category' => $cat,
'importance' => $entry->get('importance'),
'source' => $entry->get('source'),
'isPinned' => $entry->get('isPinned'),
'isArchived' => $entry->get('isArchived'),
'createdAt' => $entry->get('createdAt'),
'modifiedAt' => $entry->get('modifiedAt'),
];
}
return $grouped;
}
public function getPinnedMemories(string $caseId): array
{
$entries = $this->entityManager->getRDBRepository('CaseMemory')
->where(['caseId' => $caseId, 'isPinned' => true, 'isArchived' => false, 'deleted' => false])
->order('createdAt', 'DESC')
->find();
$result = [];
foreach ($entries as $entry) {
$result[] = [
'id' => $entry->get('id'),
'name' => $entry->get('name'),
'content' => $entry->get('content'),
'category' => $entry->get('category'),
'importance' => $entry->get('importance'),
];
}
return $result;
}
}