Backend API
$(() => {
const aiService = new AzureOpenAI({
dangerouslyAllowBrowser: true,
deployment,
endpoint,
apiVersion,
apiKey,
});
async function getAIResponse(messages, signal) {
const params = {
messages,
model: deployment,
max_tokens: 1000,
temperature: 0.7,
};
const response = await aiService.chat.completions.create(params, { signal });
const result = response.choices[0].message?.content;
return result;
}
const aiIntegration = new DevExpress.aiIntegration({
sendRequest({ prompt }) {
const controller = new AbortController();
const signal = controller.signal;
const aiPrompt = [
{ role: 'system', content: prompt.system },
{ role: 'user', content: prompt.user },
];
const promise = getAIResponse(aiPrompt, signal);
promise.catch(() => {
showNotification('Something went wrong. Please try again.', '#form', true);
});
const result = {
promise,
abort: () => {
controller.abort();
},
};
return result;
},
});
const showNotification = (message, of, isError, offset) => {
DevExpress.ui.notify({
message,
position: {
my: 'bottom center',
at: 'bottom center',
of,
offset: offset ?? '0 -50',
},
width: 'fit-content',
maxWidth: 'fit-content',
minWidth: 'fit-content',
}, isError ? 'error' : 'info', 1500);
};
const customSmartPasteHandler = () => {
navigator.clipboard.readText()
.then((text) => {
if (text) {
form.smartPaste(text);
} else {
showNotification(
'Clipboard is empty. Copy text before pasting',
'#form',
);
}
})
.catch(() => {
showNotification(
'Could not access the clipboard',
'#form',
);
});
};
const colCountByScreen = {
xs: 2,
sm: 2,
md: 2,
lg: 2,
};
const stylingMode = 'filled';
const form = $('#form').dxForm({
formData: {},
aiIntegration,
labelMode: 'outside',
showColonAfterLabel: false,
labelLocation: 'top',
minColWidth: 220,
items: [{
itemType: 'group',
caption: 'Billing Summary',
colCountByScreen,
items: [{
dataField: 'Amount Due',
editorType: 'dxTextBox',
editorOptions: {
placeholder: '$0.00',
stylingMode,
},
aiOptions: {
instruction: 'Format as the following: $0.00',
},
}, {
dataField: 'Statement Date',
editorType: 'dxDateBox',
editorOptions: {
placeholder: 'MM/DD/YYYY',
stylingMode: 'filled',
},
aiOptions: {
instruction: 'Format as the following: MM/DD/YYYY',
},
}],
}, {
itemType: 'group',
caption: 'Billing Information',
colCountByScreen,
items: [{
dataField: 'First Name',
editorType: 'dxTextBox',
editorOptions: {
stylingMode,
},
}, {
dataField: 'Last Name',
editorType: 'dxTextBox',
editorOptions: {
stylingMode,
},
}, {
dataField: 'Phone Number',
editorType: 'dxTextBox',
editorOptions: {
placeholder: '(000) 000-0000',
stylingMode,
},
aiOptions: {
instruction: 'Format as the following: (000) 000-0000',
},
}, {
dataField: 'Email',
editorType: 'dxTextBox',
editorOptions: {
stylingMode,
},
validationRules: [{ type: 'email' }],
aiOptions: {
instruction: 'Do not fill this field if the text contains an invalid email address. A valid email is in the following format: email@example.com',
},
}],
}, {
itemType: 'group',
caption: 'Billing Address',
colCountByScreen,
items: [{
dataField: 'Street Address',
editorType: 'dxTextBox',
editorOptions: {
stylingMode,
},
}, {
dataField: 'City',
editorType: 'dxTextBox',
editorOptions: {
stylingMode,
},
}, {
dataField: 'State/Province/Region',
editorType: 'dxTextBox',
editorOptions: {
stylingMode,
},
}, {
dataField: 'ZIP',
editorType: 'dxNumberBox',
editorOptions: {
stylingMode,
mode: 'text',
value: null,
},
aiOptions: {
instruction: 'If the text does not contain a ZIP, determine the ZIP code from the provided address.',
},
}],
}, {
itemType: 'group',
cssClass: 'buttons-group',
colCountByScreen,
items: [{
itemType: 'button',
name: 'smartPaste',
buttonOptions: {
stylingMode: 'contained',
type: 'default',
},
}, {
itemType: 'button',
name: 'reset',
buttonOptions: {
stylingMode: 'outlined',
type: 'normal',
},
}],
}],
}).dxForm('instance');
const textArea = $('#textarea').dxTextArea({
value: defaultText,
stylingMode,
inputAttr: { 'aria-labelledby': 'textarea-label' },
height: '100%',
}).dxTextArea('instance');
$('#copy').dxButton({
text: 'Copy Text',
icon: 'copy',
stylingMode: 'contained',
type: 'default',
width: 'fit-content',
onClick: () => {
const { value } = textArea.option();
navigator.clipboard.writeText(value);
showNotification(
'Text copied to clipboard',
'#textarea',
false,
'0 -20',
);
},
});
form.registerKeyHandler('V', (event) => {
if (event.ctrlKey && event.shiftKey) {
customSmartPasteHandler();
}
});
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>window.jQuery || document.write(decodeURIComponent('%3Cscript src="js/jquery.min.js"%3E%3C/script%3E'))</script>
<script type="module">
import { AzureOpenAI } from "https://esm.sh/openai@4.73.1";
window.AzureOpenAI = AzureOpenAI;
</script>
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/25.2.4/css/dx.light.css" />
<script src="js/dx.all.debug.js"></script>
<script src="js/dx.ai-integration.js"></script>
<script src="data.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="index.js"></script>
</head>
<body class="dx-viewport">
<div class="demo-container">
<div class="instruction" id="textarea-label">Copy text from the editor below to the clipboard. Edit the text to see how your changes affect Smart Paste result.</div>
<div class="instruction">Paste text from the clipboard to populate the form. Press Ctrl+Shift+V (when the form is focused) or use the "Smart Paste" button under the form.</div>
<div class="textarea-container">
<div id="copy"></div>
<div id="textarea"></div>
</div>
<div id="form"></div>
</div>
</body>
</html>
.demo-container {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows: auto auto;
gap: 24px 40px;
min-width: 720px;
max-width: 900px;
margin: auto;
}
.instruction {
color: var(--dx-texteditor-color-label);
}
.textarea-container {
display: flex;
flex-direction: column;
gap: 16px;
}
.dx-layout-manager .dx-field-item.dx-last-row {
padding-top: 4px;
}
.dx-toast-info .dx-toast-icon {
display: none;
}
.buttons-group {
display: flex;
width: 100%;
justify-content: end;
}
.buttons-group .dx-item-content {
gap: 8px;
}
.buttons-group .dx-field-item:not(.dx-first-col),
.buttons-group .dx-field-item:not(.dx-last-col) {
padding: 0;
}
.buttons-group .dx-item {
flex: unset !important;
}
const deployment = 'gpt-4o-mini';
const apiVersion = '2024-02-01';
const endpoint = 'https://public-api.devexpress.com/demo-openai';
const apiKey = 'DEMO';
const defaultText = `Payment: Amount - $123.00
Statement Date: 10/15/2024
Name: John Smith
Contact: (123) 456-7890
Email: john@myemail.com
Address:
- 123 Elm St Apt 4B
- New York, NY 10001
`;
Use the following APIs to activate Smart Paste in our JavaScript Form component:
- aiIntegration - accepts an AIIntegration object that contains AI Service settings.
- 'smartPaste' – adds a built-in Smart Paste button to the JavaScript Form (see name for additional information). To use this capability in code, call the smartPaste(text) method. This sample leverages this method and implements a custom shortcut to activate Smart Paste.
Configure each JavaScript Form item using aiOptions:
- disabled - prevents AI-generated text from being pasted into this item.
- instruction - specifies item instruction for the AI service.