From d0410a6f5e12aaae38be395a88b13fdbf12b6cda Mon Sep 17 00:00:00 2001 From: Amirzhan Alimov Date: Wed, 19 Mar 2025 15:48:09 +0500 Subject: [PATCH 1/3] Add error handling, fix viewer assistant creation --- CS/ReportingApp/ReportingApp.csproj | 2 +- .../Views/Home/DocumentViewer.cshtml | 4 +- CS/ReportingApp/wwwroot/js/aiIntegration.js | 55 +++++++++++++++---- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/CS/ReportingApp/ReportingApp.csproj b/CS/ReportingApp/ReportingApp.csproj index c818b30..59ae0dd 100644 --- a/CS/ReportingApp/ReportingApp.csproj +++ b/CS/ReportingApp/ReportingApp.csproj @@ -47,7 +47,7 @@ - + diff --git a/CS/ReportingApp/Views/Home/DocumentViewer.cshtml b/CS/ReportingApp/Views/Home/DocumentViewer.cshtml index 87f2ecf..c7bf8f0 100644 --- a/CS/ReportingApp/Views/Home/DocumentViewer.cshtml +++ b/CS/ReportingApp/Views/Home/DocumentViewer.cshtml @@ -5,9 +5,7 @@ async function BeforeRender(sender, args) { const previewModel = args; const reportPreview = previewModel.reportPreview; - const result = await fetch(`/AI/CreateUserAssistant`); - const chatId = await result.text(); - aiTab = createAssistantTab(chatId); + aiTab = createAssistantTab(); const model = aiTab.model; previewModel.tabPanel.tabs.push(aiTab); reportPreview.events.on('documentBuildingChanged', (args) => { diff --git a/CS/ReportingApp/wwwroot/js/aiIntegration.js b/CS/ReportingApp/wwwroot/js/aiIntegration.js index 1720642..06b37a8 100644 --- a/CS/ReportingApp/wwwroot/js/aiIntegration.js +++ b/CS/ReportingApp/wwwroot/js/aiIntegration.js @@ -1,7 +1,7 @@ -const createAssistantTab = (function() { +const createAssistantTab = (function() { let lastUserQuery; - + let errorList = []; const assistant = { id: 'assistant', name: 'Virtual Assistant', @@ -11,6 +11,29 @@ 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); @@ -23,16 +46,23 @@ navigator.clipboard.writeText(text); } - async function getAIResponse(text, id) { + async function getAIResponse(instance, 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(); + 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) { @@ -45,7 +75,7 @@ const newItems = items.slice(0, -1); instance.option({ items: newItems }); instance.option({ typingUsers: [assistant] }); - const aiResponse = await getAIResponse(lastUserQuery, assistant.id); + const aiResponse = await getAIResponse(instance, lastUserQuery, assistant.id); setTimeout(() => { instance.option({ typingUsers: [] }); RenderAssistantMessage(instance, aiResponse); @@ -53,6 +83,7 @@ } function createAssistantTab(chatId) { + let lastRefreshButton; assistant.id = chatId; const model = { title: 'AI Assistant', @@ -72,6 +103,7 @@ 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', @@ -86,15 +118,16 @@ onClick: () => refreshAnswer(data.component) }); buttonContainer.appendChild(refreshBtnElement); + lastRefreshButton = refreshBtnElement; container.appendChild(buttonContainer); }, onMessageEntered: async (e) => { const instance = e.component; + instance.option('alerts', []); instance.renderMessage(e.message); instance.option({ typingUsers: [assistant] }); const userInput = e.message.text; - - var response = await getAIResponse(userInput, assistant.id); + const response = await getAIResponse(instance, userInput, assistant.id ?? model.chatId); RenderAssistantMessage(instance, response); } }; From bd73b49b641dd6000c6ca2af9ec85626f6a4414a Mon Sep 17 00:00:00 2001 From: DevExpressExampleBot Date: Wed, 19 Mar 2025 14:51:46 +0400 Subject: [PATCH 2/3] README auto update [skip ci] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b577066..ca3aa89 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -![](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) From b0491a8dbfbbc8a3d468cfd2607fdb606b5d705b Mon Sep 17 00:00:00 2001 From: Amirzhan Alimov Date: Wed, 19 Mar 2025 15:54:00 +0500 Subject: [PATCH 3/3] fix spaces --- CS/ReportingApp/wwwroot/js/aiIntegration.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CS/ReportingApp/wwwroot/js/aiIntegration.js b/CS/ReportingApp/wwwroot/js/aiIntegration.js index 06b37a8..55278d3 100644 --- a/CS/ReportingApp/wwwroot/js/aiIntegration.js +++ b/CS/ReportingApp/wwwroot/js/aiIntegration.js @@ -15,8 +15,7 @@ const createAssistantTab = (function() { async function _tryFetch(instance, fetchAction, message) { try { return await fetchAction(); - } - catch(error) { + } catch(error) { _handleError(instance, { message: error.message, code: message }); } }