Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,8 @@ TesterMetadata.xml
package-lock.json

.angular/
**/wwwroot/css/ace
**/wwwroot/css/icons/
**/wwwroot/css/*bundle.css
**/wwwroot/css/*skeleton-screen.css
**/wwwroot/js/*bundle.js
6 changes: 3 additions & 3 deletions CS/ReportingApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"license": "MIT",
"private": true,
"dependencies": {
"@devexpress/analytics-core": "24.2.2-beta",
"@devexpress/analytics-core": "24.2-stable",
"bootstrap": "^4.3.1",
"devexpress-reporting": "24.2.2-beta",
"devextreme-dist": "24.2.2-beta",
"devexpress-reporting": "24.2-stable",
"devextreme-dist": "24.2-stable",
"marked": "^14.1.3"
}
}
6 changes: 6 additions & 0 deletions CS/ReportingApp/wwwroot/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,9 @@ min-height: 100%;
line-height: 50px;
height: 60px;
}

.dx-chat-messagegroup-alignment-start:last-child .dx-chat-messagebubble:last-child .dx-bubble-button-containder {
display: flex;
gap: 4px;
margin-top: 8px;
}
107 changes: 84 additions & 23 deletions CS/ReportingApp/wwwroot/js/aiIntegration.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,107 @@
function normilizeAIResponse(text) {

let lastUserQuery;

const assistant = {
id: 'assistant',
name: 'Virtual Assistant',
};

const user = {
id: 'user',
};

function normilizeAIResponse(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(text, id) {
const formData = new FormData();
formData.append('text', text);
formData.append('chatId', id);
lastUserQuery = text;
const response = await fetch(`/AI/GetAnswer`, {
method: 'POST',
body: formData
});
return await response.text();
}

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(lastUserQuery, assistant.id);
setTimeout(() => {
instance.option({ typingUsers: [] });
RenderAssistantMessage(instance, aiResponse);
}, 200);
}

function createAssistantTab(chatId) {
assistant.id = chatId;
const model = {
title: 'AI Assistant',
chatId: chatId,
showAvatar: false,
showUserName: false,
showMessageTimestamp: false,
user: {
id: 1,
},
user: user,
messageTemplate: (data, container) => {
if(data.message.author.id === 'Assistant')
return normilizeAIResponse(data.message.text);
return data.message.text;
const { message } = data;

if (message.author.id && message.author.id !== assistant.id)
return message.text;

const $textElement = $('<div>')
.html(normilizeAIResponse(message.text))
.appendTo(container);
const $buttonContainer = $('<div>')
.addClass('dx-bubble-button-containder');
$('<div>')
.dxButton({
icon: 'copy',
stylingMode: 'text',
onClick: () => {
const text = $textElement.text();
copyText(text);
}
})
.appendTo($buttonContainer);
$('<div>')
.dxButton({
icon: 'refresh',
stylingMode: 'text',
onClick: () => {
refreshAnswer(data.component);
},
})
.appendTo($buttonContainer);
$buttonContainer.appendTo(container);
},
onMessageEntered: (e) => {
onMessageEntered: async (e) => {
const instance = e.component;
instance.renderMessage(e.message);
instance.option({ typingUsers: [assistant] });
const userInput = e.message.text;

const formData = new FormData();
formData.append('text', e.message.text);
formData.append('chatId', model.chatId);
fetch(`/AI/GetAnswer`, {
method: 'POST',
body: formData
}).then((x) => {
x.text().then((res) => {
instance.renderMessage({
text: res,
author: { id: 'Assistant' }
}, { id: 'Assistant' });
});
});
var response = await getAIResponse(userInput, assistant.id);
RenderAssistantMessage(instance, response);
}
};

return new DevExpress.Analytics.Utils.TabInfo({
text: 'AI Assistant',
template: 'dxrd-ai-panel',
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<!-- default badges list -->
![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/853003889/24.2.2%2B)
[![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T1252182)
[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183)
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
Expand Down
Loading