-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaiIntegration.js
152 lines (135 loc) · 5.39 KB
/
aiIntegration.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
const createAssistantTab = (function() {
let lastUserQuery;
let errorList = [];
const assistant = {
id: 'assistant',
name: 'Virtual Assistant',
};
const user = {
id: 'user',
};
async function _tryFetch(instance, fetchAction, message) {
try {
return await fetchAction();
} catch(error) {
_handleError(instance, { message: error.message, code: message });
}
}
function _handleError(instance, error) {
const id = "id" + Math.random().toString(16).slice(2)
setTimeout(() => {
errorList = errorList.filter(err => err.id !== id);
instance.option('alerts', errorList);
}, 10000);
errorList.push({
id: id,
message: `${error.code} - ${error.message}`
});
instance.option('alerts', errorList);
}
function normalizeAIResponse(text) {
text = text.replace(/【\d+:\d+†[^\】]+】/g, "");
let html = marked.parse(text);
if(/<p>\.\s*<\/p>\s*$/.test(html))
html = html.replace(/<p>\.\s*<\/p>\s*$/, "")
return html;
}
function copyText(text) {
navigator.clipboard.writeText(text);
}
async function getAIResponse(instance, text, id) {
const formData = new FormData();
formData.append('text', text);
formData.append('chatId', id);
lastUserQuery = text;
return _tryFetch(instance, async () => {
const response = await fetch('/AI/GetAnswer', {
method: 'POST',
body: formData
});
if(!response.ok) {
_handleError(instance, { code: `${response.status}`, message: `Internal server error` });
return;
}
return await response.text();
}, 'GetAnswer');
}
function RenderAssistantMessage(instance, message) {
instance.option({ typingUsers: [] });
instance.renderMessage({ timestamp: new Date(), text: message, author: assistant.name, id: assistant.id });
}
async function refreshAnswer(instance) {
const items = instance.option('items');
const newItems = items.slice(0, -1);
instance.option({ items: newItems });
instance.option({ typingUsers: [assistant] });
const aiResponse = await getAIResponse(instance, lastUserQuery, assistant.id);
setTimeout(() => {
instance.option({ typingUsers: [] });
RenderAssistantMessage(instance, aiResponse);
}, 200);
}
function createAssistantTab(chatId) {
let lastRefreshButton;
assistant.id = chatId;
const model = {
title: 'AI Assistant',
showAvatar: false,
showUserName: false,
showMessageTimestamp: false,
user: user,
messageTemplate: (data, $container) => {
const { message } = data;
const container = $container.jquery ? $container.get(0) : $container;
if(message.author.id && message.author.id !== assistant.id)
return message.text;
const textElement = document.createElement('div');
textElement.innerHTML = normalizeAIResponse(message.text);
container.appendChild(textElement)
const buttonContainer = document.createElement('div');
buttonContainer.classList.add('dx-bubble-button-container');
lastRefreshButton?.remove();
const copyBtnElement = document.createElement('div');
new DevExpress.ui.dxButton(copyBtnElement, {
icon: 'copy',
stylingMode: 'text',
onClick: () => copyText(textElement.textContent)
});
buttonContainer.appendChild(copyBtnElement);
const refreshBtnElement = document.createElement('div');
new DevExpress.ui.dxButton(refreshBtnElement, {
icon: 'refresh',
stylingMode: 'text',
onClick: () => refreshAnswer(data.component)
});
if(data.component.option('items').at(-1).author === assistant.name) {
buttonContainer.appendChild(refreshBtnElement);
lastRefreshButton = refreshBtnElement;
}
container.appendChild(buttonContainer);
},
onMessageEntered: async (e) => {
lastRefreshButton?.remove();
const instance = e.component;
instance.option('alerts', []);
instance.renderMessage(e.message);
instance.option({ typingUsers: [assistant] });
const userInput = e.message.text;
if(!assistant.id && model.chatId) {
assistant.id = model.chatId;
}
const response = await getAIResponse(instance, userInput, assistant.id);
RenderAssistantMessage(instance, response);
}
};
return new DevExpress.Analytics.Utils.TabInfo({
text: 'AI Assistant',
template: 'dxrd-ai-panel',
imageTemplateName: 'dxrd-ai-icon',
imageClassName: 'aitab',
model: model
});
}
return createAssistantTab;
})();
window.createAssistantTab = createAssistantTab;