From 37533109975de7cbe1f5f7478a044cb697b5f588 Mon Sep 17 00:00:00 2001 From: Alexander Kozlovskiy Date: Wed, 11 Dec 2024 13:16:56 +0400 Subject: [PATCH] Chat - Ai chat demo fixes for React and Vue --- .../AIAndChatbotIntegration/React/App.tsx | 2 +- .../AIAndChatbotIntegration/ReactJs/App.js | 79 ++++++----------- .../ReactJs/Message.js | 88 ++++++++----------- .../AIAndChatbotIntegration/ReactJs/data.js | 5 +- .../AIAndChatbotIntegration/ReactJs/index.js | 6 +- .../Chat/AIAndChatbotIntegration/Vue/App.vue | 4 +- 6 files changed, 71 insertions(+), 113 deletions(-) diff --git a/apps/demos/Demos/Chat/AIAndChatbotIntegration/React/App.tsx b/apps/demos/Demos/Chat/AIAndChatbotIntegration/React/App.tsx index 4cba5ee4f435..a1932183a81b 100644 --- a/apps/demos/Demos/Chat/AIAndChatbotIntegration/React/App.tsx +++ b/apps/demos/Demos/Chat/AIAndChatbotIntegration/React/App.tsx @@ -35,7 +35,7 @@ async function getAIResponse(messages) { temperature: 0.7, }; - const response = await chatService.chat.completions.create(params); + const response = await chatService.chat.completions.create(params as any); const data = { choices: response.choices }; return data.choices[0].message?.content; diff --git a/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/App.js b/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/App.js index 8f898bb238c3..530bf543a2c2 100644 --- a/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/App.js +++ b/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/App.js @@ -4,19 +4,18 @@ import { AzureOpenAI } from 'openai'; import CustomStore from 'devextreme/data/custom_store'; import DataSource from 'devextreme/data/data_source'; import { loadMessages } from 'devextreme/localization'; -import { +import { user, assistant, AzureOpenAIConfig, REGENERATION_TEXT, CHAT_DISABLED_CLASS, - ALERT_TIMEOUT + ALERT_TIMEOUT, } from './data.js'; import Message from './Message.js'; const store = []; const messages = []; - loadMessages({ en: { 'dxChat-emptyListMessage': 'Chat is Empty', @@ -24,33 +23,28 @@ loadMessages({ 'dxChat-textareaPlaceholder': 'Ask AI Assistant...', }, }); - const chatService = new AzureOpenAI(AzureOpenAIConfig); - async function getAIResponse(messages) { const params = { messages, max_tokens: 1000, temperature: 0.7, }; - const response = await chatService.chat.completions.create(params); const data = { choices: response.choices }; - return data.choices[0].message?.content; } - function updateLastMessage(text = REGENERATION_TEXT) { const items = dataSource.items(); const lastMessage = items.at(-1); - - dataSource.store().push([{ - type: 'update', - key: lastMessage.id, - data: { text }, - }]); + dataSource.store().push([ + { + type: 'update', + key: lastMessage.id, + data: { text }, + }, + ]); } - function renderAssistantMessage(text) { const message = { id: Date.now(), @@ -58,68 +52,54 @@ function renderAssistantMessage(text) { author: assistant, text, }; - dataSource.store().push([{ type: 'insert', data: message }]); } - const customStore = new CustomStore({ key: 'id', - load: () => { - return new Promise((resolve) => { - setTimeout(() => { - resolve([...store]); - }, 0); - }); - }, - insert: (message) => { - return new Promise((resolve) => { - setTimeout(() => { - store.push(message); - resolve(message); - }); + load: () => new Promise((resolve) => { + setTimeout(() => { + resolve([...store]); + }, 0); + }), + insert: (message) => new Promise((resolve) => { + setTimeout(() => { + store.push(message); + resolve(message); }); - }, + }), }); - const dataSource = new DataSource({ store: customStore, paginate: false, -}) - +}); export default function App() { const [alerts, setAlerts] = useState([]); const [typingUsers, setTypingUsers] = useState([]); const [classList, setClassList] = useState(''); - function alertLimitReached() { - setAlerts([{ - message: 'Request limit reached, try again in a minute.' - }]); - + setAlerts([ + { + message: 'Request limit reached, try again in a minute.', + }, + ]); setTimeout(() => { setAlerts([]); }, ALERT_TIMEOUT); } - function toggleDisabledState(disabled, event = undefined) { setClassList(disabled ? CHAT_DISABLED_CLASS : ''); - if (disabled) { event?.target.blur(); } else { event?.target.focus(); } - }; - + } async function processMessageSending(message, event) { toggleDisabledState(true, event); - messages.push({ role: 'user', content: message.text }); setTypingUsers([assistant]); - try { const aiResponse = await getAIResponse(messages); - setTimeout(() => { setTypingUsers([]); messages.push({ role: 'assistant', content: aiResponse }); @@ -133,13 +113,10 @@ export default function App() { toggleDisabledState(false, event); } } - async function regenerate() { toggleDisabledState(true); - try { const aiResponse = await getAIResponse(messages.slice(0, -1)); - updateLastMessage(aiResponse); messages.at(-1).content = aiResponse; } catch { @@ -149,20 +126,16 @@ export default function App() { toggleDisabledState(false); } } - function onMessageEntered({ message, event }) { dataSource.store().push([{ type: 'insert', data: { id: Date.now(), ...message } }]); - if (!alerts.length) { processMessageSending(message, event); } } - function onRegenerateButtonClick() { updateLastMessage(); regenerate(); } - return ( {REGENERATION_TEXT}; - } - - function onCopyButtonClick() { - navigator.clipboard?.writeText(message.text); - setIcon('check'); - - setTimeout(() => { - setIcon('copy'); - }, 2500); - } - - return ( - -
- {HTMLReactParser(convertToHtml(message.text))} -
-
-
-
- ) + const [icon, setIcon] = useState('copy'); + if (message.text === REGENERATION_TEXT) { + return {REGENERATION_TEXT}; + } + function onCopyButtonClick() { + navigator.clipboard?.writeText(message.text); + setIcon('check'); + setTimeout(() => { + setIcon('copy'); + }, 2500); + } + return ( + +
+ {HTMLReactParser(convertToHtml(message.text))} +
+
+
+
+ ); } - export default Message; diff --git a/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/data.js b/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/data.js index 3a66e2b837f0..8478f018409e 100644 --- a/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/data.js +++ b/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/data.js @@ -4,16 +4,13 @@ export const AzureOpenAIConfig = { apiVersion: '2024-02-01', endpoint: 'https://public-api.devexpress.com/demo-openai', apiKey: 'DEMO', -} - +}; export const REGENERATION_TEXT = 'Regeneration...'; export const CHAT_DISABLED_CLASS = 'dx-chat-disabled'; export const ALERT_TIMEOUT = 1000 * 60; - export const user = { id: 'user', }; - export const assistant = { id: 'assistant', name: 'Virtual Assistant', diff --git a/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/index.js b/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/index.js index d9d7442ce766..b853e0be8242 100644 --- a/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/index.js +++ b/apps/demos/Demos/Chat/AIAndChatbotIntegration/ReactJs/index.js @@ -1,9 +1,5 @@ import React from 'react'; import ReactDOM from 'react-dom'; - import App from './App.js'; -ReactDOM.render( - , - document.getElementById('app'), -); +ReactDOM.render(, document.getElementById('app')); diff --git a/apps/demos/Demos/Chat/AIAndChatbotIntegration/Vue/App.vue b/apps/demos/Demos/Chat/AIAndChatbotIntegration/Vue/App.vue index 7d79c37f6389..138cd645913d 100644 --- a/apps/demos/Demos/Chat/AIAndChatbotIntegration/Vue/App.vue +++ b/apps/demos/Demos/Chat/AIAndChatbotIntegration/Vue/App.vue @@ -67,7 +67,7 @@ import { ALERT_TIMEOUT, } from './data.ts'; -const chatService = new AzureOpenAI(AzureOpenAIConfig); +let chatService; const typingUsers = ref([]); const alerts = ref([]); @@ -76,6 +76,8 @@ const copyButtonIcon = ref('copy'); onBeforeMount(() => { loadMessages(dictionary); + + chatService = new AzureOpenAI(AzureOpenAIConfig); }); async function getAIResponse(messages) {