Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f77631f75 | |||
| 81fa5f3a08 | |||
| cf0e9ad2bc | |||
| 07df19b412 | |||
| b9542e3980 | |||
| 4f5b6be884 |
@@ -1,6 +1,6 @@
|
|||||||
# SmartAssistant - עוזר חכם
|
# SmartAssistant - עוזר חכם
|
||||||
|
|
||||||
**גרסה:** 1.1.2 | **מחבר:** klear | **EspoCRM:** >= 8.0.0
|
**גרסה:** 1.1.7 | **מחבר:** klear | **EspoCRM:** >= 8.0.0
|
||||||
|
|
||||||
## תיאור
|
## תיאור
|
||||||
עוזר AI מאוחד למשרד עורכי דין. מספק ממשק צ'אט צף עם שני מצבי עבודה: **מצב משרד** (סקירה כללית, התראות, סטטיסטיקות) ו**מצב תיק** (סיוע מעמיק בתיק ספציפי). כולל מערכת זיכרון תיק מובנית, ביצוע פעולות באישור המשתמש, ואינטגרציה עם Stream של EspoCRM.
|
עוזר AI מאוחד למשרד עורכי דין. מספק ממשק צ'אט צף עם שני מצבי עבודה: **מצב משרד** (סקירה כללית, התראות, סטטיסטיקות) ו**מצב תיק** (סיוע מעמיק בתיק ספציפי). כולל מערכת זיכרון תיק מובנית, ביצוע פעולות באישור המשתמש, ואינטגרציה עם Stream של EspoCRM.
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ define('modules/smart-assistant/views/dashlets/smart-assistant', ['view'], funct
|
|||||||
},
|
},
|
||||||
|
|
||||||
showDetail: function (type) {
|
showDetail: function (type) {
|
||||||
|
var self = this;
|
||||||
var $detail = this.$el.find('.sa-dashlet-detail');
|
var $detail = this.$el.find('.sa-dashlet-detail');
|
||||||
|
|
||||||
if (!type || type === this._activeType && $detail.html()) {
|
if (!type || type === this._activeType && $detail.html()) {
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
|
|
||||||
self.$el.find('.sa-fab').show();
|
self.$el.find('.sa-fab').show();
|
||||||
self.$el.find('.sa-chat-messages').attr('data-empty-text',
|
self.$el.find('.sa-chat-messages').attr('data-empty-text',
|
||||||
self.translate('Chat with the assistant', 'labels', 'SmartAssistant') || 'שוחח/י עם העוזר החכם');
|
self.translate('Chat with the assistant', 'labels', 'SmartAssistant') || 'שוחח/י עם שירה');
|
||||||
self.loadAlertCount();
|
self.loadAlertCount();
|
||||||
self._setupRouteListener();
|
self._setupRouteListener();
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
@@ -417,7 +417,7 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
|
|
||||||
$messages.append('<div class="sa-msg sa-msg-user">' + this.escapeHtml(message) + '</div>');
|
$messages.append('<div class="sa-msg sa-msg-user">' + this.escapeHtml(message) + '</div>');
|
||||||
var $loading = $('<div class="sa-msg sa-msg-loading"><span class="fas fa-spinner fa-spin" style="margin-left: 5px;"></span> ' +
|
var $loading = $('<div class="sa-msg sa-msg-loading"><span class="fas fa-spinner fa-spin" style="margin-left: 5px;"></span> ' +
|
||||||
this.escapeHtml(this.translate('Thinking', 'labels', 'SmartAssistant') || 'חושב...') + '</div>');
|
this.escapeHtml(this.translate('Thinking', 'labels', 'SmartAssistant') || 'חושבת...') + '</div>');
|
||||||
$messages.append($loading);
|
$messages.append($loading);
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
|
|
||||||
@@ -480,6 +480,10 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
var cls = approved ? (result.success ? 'sa-msg-assistant' : 'sa-msg-error') : 'sa-msg-loading';
|
var cls = approved ? (result.success ? 'sa-msg-assistant' : 'sa-msg-error') : 'sa-msg-loading';
|
||||||
$messages.append('<div class="sa-msg ' + cls + '">' + self.escapeHtml(msg) + '</div>');
|
$messages.append('<div class="sa-msg ' + cls + '">' + self.escapeHtml(msg) + '</div>');
|
||||||
self.scrollToBottom();
|
self.scrollToBottom();
|
||||||
|
|
||||||
|
if (approved && result.success) {
|
||||||
|
self.refreshCurrentView(result.entityType);
|
||||||
|
}
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
$messages.append('<div class="sa-msg sa-msg-error">שגיאה בביצוע הפעולה</div>');
|
$messages.append('<div class="sa-msg sa-msg-error">שגיאה בביצוע הפעולה</div>');
|
||||||
self.scrollToBottom();
|
self.scrollToBottom();
|
||||||
@@ -620,5 +624,37 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
div.textContent = text;
|
div.textContent = text;
|
||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
refreshCurrentView: function (entityType) {
|
||||||
|
var mainView = this.getParentView();
|
||||||
|
|
||||||
|
while (mainView && mainView.getParentView()) {
|
||||||
|
mainView = mainView.getParentView();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mainView) return;
|
||||||
|
|
||||||
|
var currentView = mainView.getView('main');
|
||||||
|
|
||||||
|
if (!currentView) return;
|
||||||
|
|
||||||
|
var recordView = currentView.getView('record');
|
||||||
|
|
||||||
|
if (recordView && recordView.model) {
|
||||||
|
recordView.model.trigger('update-all');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityType === 'Task' || entityType === 'Meeting') {
|
||||||
|
var sideView = currentView.getView('side');
|
||||||
|
|
||||||
|
if (sideView) {
|
||||||
|
var activities = sideView.getView('activities');
|
||||||
|
var tasks = sideView.getView('tasks');
|
||||||
|
|
||||||
|
if (activities && activities.actionRefresh) activities.actionRefresh();
|
||||||
|
if (tasks && tasks.actionRefresh) tasks.actionRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ define('modules/smart-assistant/views/stream/notes/smart-action', ['views/stream
|
|||||||
templateContent: '' +
|
templateContent: '' +
|
||||||
'<div class="sa-action-note sa-action-{{status}}" style="padding: 6px 12px; border-radius: 8px; direction: rtl; text-align: right; font-size: 13px;">' +
|
'<div class="sa-action-note sa-action-{{status}}" style="padding: 6px 12px; border-radius: 8px; direction: rtl; text-align: right; font-size: 13px;">' +
|
||||||
'<span class="fas {{icon}}" style="margin-left: 6px;"></span>' +
|
'<span class="fas {{icon}}" style="margin-left: 6px;"></span>' +
|
||||||
'{{post}}' +
|
'{{{formattedPost}}}' +
|
||||||
'</div>',
|
'</div>',
|
||||||
|
|
||||||
data: function () {
|
data: function () {
|
||||||
@@ -13,6 +13,8 @@ define('modules/smart-assistant/views/stream/notes/smart-action', ['views/stream
|
|||||||
var noteData = this.model.get('data') || {};
|
var noteData = this.model.get('data') || {};
|
||||||
var status = noteData.status || 'executed';
|
var status = noteData.status || 'executed';
|
||||||
|
|
||||||
|
data.post = this.model.get('post');
|
||||||
|
data.formattedPost = this.getHelper().escapeString(data.post || '');
|
||||||
data.status = status;
|
data.status = status;
|
||||||
|
|
||||||
if (status === 'executed') {
|
if (status === 'executed') {
|
||||||
|
|||||||
+14
-3
@@ -5,11 +5,22 @@ define('modules/smart-assistant/views/stream/notes/smart-request', ['views/strea
|
|||||||
templateContent: '' +
|
templateContent: '' +
|
||||||
'<div style="background: #e3f2fd; padding: 8px 12px; border-radius: 8px; direction: rtl; text-align: right; font-size: 13px;">' +
|
'<div style="background: #e3f2fd; padding: 8px 12px; border-radius: 8px; direction: rtl; text-align: right; font-size: 13px;">' +
|
||||||
'<span class="fas fa-user" style="color: #1565c0; margin-left: 6px;"></span>' +
|
'<span class="fas fa-user" style="color: #1565c0; margin-left: 6px;"></span>' +
|
||||||
'{{post}}' +
|
'{{{formattedPost}}}' +
|
||||||
'</div>',
|
'</div>',
|
||||||
|
|
||||||
setup: function () {
|
data: function () {
|
||||||
NoteView.prototype.setup.call(this);
|
var data = NoteView.prototype.data.call(this);
|
||||||
|
|
||||||
|
data.formattedPost = this.formatPost(this.model.get('post'));
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
formatPost: function (text) {
|
||||||
|
if (!text) return '';
|
||||||
|
text = this.getHelper().escapeString(text);
|
||||||
|
text = text.replace(/\n/g, '<br>');
|
||||||
|
return text;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
"Smart Assistant": "שירה",
|
"Smart Assistant": "שירה",
|
||||||
"Office Mode": "מצב משרד",
|
"Office Mode": "מצב משרד",
|
||||||
"Case Mode": "מצב תיק",
|
"Case Mode": "מצב תיק",
|
||||||
"Add Memory": "הוסף זיכרון",
|
"Add Memory": "הוספת זיכרון",
|
||||||
"Search Memory": "חפש בזיכרון",
|
"Search Memory": "חיפוש בזיכרון",
|
||||||
"New Conversation": "שיחה חדשה",
|
"New Conversation": "שיחה חדשה",
|
||||||
"Conversation History": "היסטוריית שיחות",
|
"Conversation History": "היסטוריית שיחות",
|
||||||
"Previous Conversations": "שיחות קודמות",
|
"Previous Conversations": "שיחות קודמות",
|
||||||
"No previous conversations": "אין שיחות קודמות",
|
"No previous conversations": "אין שיחות קודמות",
|
||||||
"Ask the assistant...": "שאל/י את שירה...",
|
"Ask the assistant...": "שאל/י את שירה...",
|
||||||
"Thinking": "חושב...",
|
"Thinking": "חושבת...",
|
||||||
"Error": "שגיאה בתקשורת",
|
"Error": "שגיאה בתקשורת",
|
||||||
"Back": "חזרה",
|
"Back": "חזרה",
|
||||||
"Chat with the assistant": "שוחח/י עם שירה",
|
"Chat with the assistant": "שוחח/י עם שירה",
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"itemViews": {
|
||||||
|
"SmartRequest": "modules/smart-assistant/views/stream/notes/smart-request",
|
||||||
|
"SmartResponse": "modules/smart-assistant/views/stream/notes/smart-response",
|
||||||
|
"SmartAction": "modules/smart-assistant/views/stream/notes/smart-action"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,8 +55,7 @@ class ConversationRepository
|
|||||||
if (!$entity) return;
|
if (!$entity) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$messages = $entity->get('messagesData') ?? [];
|
$messages = json_decode(json_encode($entity->get('messagesData') ?? []), true);
|
||||||
if (is_object($messages)) $messages = (array) $messages;
|
|
||||||
|
|
||||||
$newMessage = ['role' => $role, 'content' => $content, 'timestamp' => date('Y-m-d H:i:s')];
|
$newMessage = ['role' => $role, 'content' => $content, 'timestamp' => date('Y-m-d H:i:s')];
|
||||||
if (!empty($actions)) $newMessage['actions'] = $actions;
|
if (!empty($actions)) $newMessage['actions'] = $actions;
|
||||||
@@ -81,8 +80,7 @@ class ConversationRepository
|
|||||||
$entity = $this->entityManager->getRDBRepository('AssistantConversation')
|
$entity = $this->entityManager->getRDBRepository('AssistantConversation')
|
||||||
->where(['conversationKey' => $conversationKey, 'deleted' => false])->findOne();
|
->where(['conversationKey' => $conversationKey, 'deleted' => false])->findOne();
|
||||||
if (!$entity) return [];
|
if (!$entity) return [];
|
||||||
$messages = $entity->get('messagesData') ?? [];
|
return json_decode(json_encode($entity->get('messagesData') ?? []), true);
|
||||||
return is_object($messages) ? (array) $messages : $messages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRecentConversations(?string $type = null, ?string $caseId = null, int $limit = 20): array
|
public function getRecentConversations(?string $type = null, ?string $caseId = null, int $limit = 20): array
|
||||||
@@ -137,8 +135,7 @@ class ConversationRepository
|
|||||||
->where(['conversationKey' => $conversationKey, 'deleted' => false])->findOne();
|
->where(['conversationKey' => $conversationKey, 'deleted' => false])->findOne();
|
||||||
if (!$entity) return;
|
if (!$entity) return;
|
||||||
|
|
||||||
$data = $entity->get('messagesData') ?? [];
|
$data = json_decode(json_encode($entity->get('messagesData') ?? []), true);
|
||||||
if (is_object($data)) $data = (array) $data;
|
|
||||||
for ($i = count($data) - 1; $i >= 0; $i--) {
|
for ($i = count($data) - 1; $i >= 0; $i--) {
|
||||||
if (($data[$i]['role'] ?? '') === 'assistant') { $data[$i]['pendingActions'] = $actions; break; }
|
if (($data[$i]['role'] ?? '') === 'assistant') { $data[$i]['pendingActions'] = $actions; break; }
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "SmartAssistant",
|
"name": "SmartAssistant",
|
||||||
"module": "SmartAssistant",
|
"module": "SmartAssistant",
|
||||||
"description": "Unified AI Assistant for Legal CRM — floating chat with case memory, office alerts, and n8n integration",
|
"description": "Unified AI Assistant for Legal CRM — floating chat with case memory, office alerts, and AI Gateway integration",
|
||||||
"author": "klear",
|
"author": "klear",
|
||||||
"version": "1.1.2",
|
"version": "2.0.0",
|
||||||
"acceptableVersions": [
|
"acceptableVersions": [
|
||||||
">=8.0.0"
|
">=8.0.0"
|
||||||
],
|
],
|
||||||
"releaseDate": "2026-03-29",
|
"releaseDate": "2026-04-04",
|
||||||
"php": [
|
"php": [
|
||||||
">=8.1"
|
">=8.1"
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user