1- import { NgModule , Component , enableProdMode } from '@angular/core' ;
1+ import { NgModule , Component , ViewChild , enableProdMode } from '@angular/core' ;
22import { BrowserModule } from '@angular/platform-browser' ;
33import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' ;
4- import { DxDataGridModule } from 'devextreme-angular' ;
5- import { Customer , Service } from './app.service' ;
4+ import {
5+ DxTextAreaModule ,
6+ DxFormModule ,
7+ DxFormComponent ,
8+ DxDateBoxModule ,
9+ DxButtonModule
10+ } from 'devextreme-angular' ;
11+ import {
12+ AIIntegration ,
13+ RequestParams ,
14+ Response ,
15+ } from 'devextreme-angular/common/ai-integration' ;
16+ import notify from 'devextreme/ui/notify' ;
17+ import { AzureOpenAI , OpenAI } from 'openai' ;
18+ import { Service } from './app.service' ;
19+ import { ButtonStyle } from 'devextreme-angular/common' ;
20+ import type { ValueChangedEvent } from 'devextreme/ui/text_area' ;
621
722if ( ! / l o c a l h o s t / . test ( document . location . host ) ) {
823 enableProdMode ( ) ;
@@ -14,23 +29,165 @@ if (window && window.config?.packageConfigPaths) {
1429 modulePrefix = '/app' ;
1530}
1631
32+ const stylingMode = 'filled' ;
33+
34+ type AIMessage = ( OpenAI . ChatCompletionUserMessageParam | OpenAI . ChatCompletionSystemMessageParam ) & {
35+ content : string ;
36+ } ;
37+
38+ const sendNotification = ( message , of , offset ) => {
39+ notify ( {
40+ message,
41+ position : {
42+ my : "bottom center" ,
43+ at : "bottom center" ,
44+ of,
45+ offset : offset ?? '0 -50' ,
46+ } ,
47+ width : 'fit-content' ,
48+ maxWidth : 'fit-content' ,
49+ minWidth : 'fit-content' ,
50+ } , 'info' , 1500 ) ;
51+ }
52+
1753@Component ( {
1854 selector : 'demo-app' ,
1955 templateUrl : `.${ modulePrefix } /app.component.html` ,
56+ styleUrls : [ `.${ modulePrefix } /app.component.css` ] ,
2057 providers : [ Service ] ,
2158} )
2259export class AppComponent {
23- customers : Customer [ ] ;
60+ @ViewChild ( DxFormComponent , { static : false } ) form : DxFormComponent ;
61+
62+ colCountByScreen = {
63+ xs : 2 ,
64+ sm : 2 ,
65+ md : 2 ,
66+ lg : 2 ,
67+ } ;
68+
69+ amountDueEditorOptions = { placeholder : '$0.00' , stylingMode } ;
70+ amountDueAIOptions = { instruction : 'Format as the following: $0.00' } ;
71+
72+ statementDueEditorOptions = { placeholder : 'MM/DD/YYYY' , stylingMode } ;
73+ statementDueAIOptions = { instruction : 'Format as the following: MM/DD/YYYY' } ;
74+
75+ textEditorOptions = { stylingMode } ;
76+
77+ phoneEditorOptions = { placeholder : '(000) 000-0000' , stylingMode } ;
78+ phoneAIOptions = { instruction : 'Format as the following: (000) 000-0000' } ;
79+
80+ emailAIOptions = { 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' } ;
81+
82+ zipEditorOptions = { stylingMode, mode : 'text' , value : null } ;
83+ zipAIOptions = { instruction : 'If the text does not contain a ZIP, determine the ZIP code from the provided address.' } ;
84+
85+ resetButtonOptions = {
86+ stylingMode : 'outlined' as ButtonStyle ,
87+ type : 'normal'
88+ } ;
89+
90+ smartPasteButtonOptions = {
91+ stylingMode : 'contained' as ButtonStyle ,
92+ type : 'default' ,
93+ }
94+
95+ azureOpenAIConfig : any ;
96+
97+ aiService : AzureOpenAI ;
98+
99+ aiIntegration : AIIntegration ;
100+
101+ valueContent : string ;
102+
103+ text : string ;
24104
25105 constructor ( service : Service ) {
26- this . customers = service . getCustomers ( ) ;
106+ this . azureOpenAIConfig = service . getAzureOpenAIConfig ( ) ;
107+
108+ this . aiService = new AzureOpenAI ( this . azureOpenAIConfig ) ;
109+ this . aiIntegration = new AIIntegration ( {
110+ sendRequest : this . sendRequest . bind ( this ) ,
111+ } ) ;
112+
113+ this . text = service . getDefaultText ( ) ;
114+ }
115+
116+ ngAfterViewInit ( ) {
117+ const form = this . form . instance ;
118+
119+ form . registerKeyHandler ( 'V' , ( event : KeyboardEvent ) => {
120+ if ( event . ctrlKey && event . shiftKey ) {
121+ navigator . clipboard . readText ( )
122+ . then ( ( clipboardText ) => {
123+ if ( clipboardText ) {
124+ form . smartPaste ( clipboardText ) ; ;
125+ } else {
126+ sendNotification ( 'Copy the text to paste into the form' , '#form' ) ;
127+ }
128+ } )
129+ . catch ( ( ) => {
130+ sendNotification ( 'Could not access the clipboard' , '#form' ) ;
131+ } ) ;
132+ }
133+ } ) ;
134+ }
135+
136+ sendRequest ( { prompt } : RequestParams ) : Response {
137+ const controller = new AbortController ( ) ;
138+ const signal = controller . signal ;
139+
140+ const aiPrompt : AIMessage [ ] = [
141+ { role : 'system' , content : prompt . system , } ,
142+ { role : 'user' , content : prompt . user , } ,
143+ ] ;
144+ const promise = this . getAIResponse ( aiPrompt , signal ) ;
145+
146+ const result : Response = {
147+ promise,
148+ abort : ( ) => {
149+ controller . abort ( ) ;
150+ } ,
151+ } ;
152+
153+ return result ;
154+ }
155+
156+ async getAIResponse ( messages : AIMessage [ ] , signal : AbortSignal ) {
157+ const params = {
158+ messages,
159+ model : this . azureOpenAIConfig . deployment ,
160+ max_tokens : 1000 ,
161+ temperature : 0.7 ,
162+ } ;
163+
164+ const response = await this . aiService . chat . completions . create ( params , { signal } ) ;
165+ const result = response . choices [ 0 ] . message ?. content ;
166+
167+ return result ;
168+ }
169+
170+ onCopy ( ) {
171+ navigator . clipboard . writeText ( this . text ) ;
172+ sendNotification ( 'Text copied to clipboard' , '#textarea' , '0 -20' ) ;
173+ }
174+
175+ setText ( event : ValueChangedEvent ) {
176+ this . text = event . value ;
177+ }
178+
179+ smartPaste ( ) {
180+ form . instance ( ) . smartPaste ( ) ;
27181 }
28182}
29183
30184@NgModule ( {
31185 imports : [
32186 BrowserModule ,
33- DxDataGridModule ,
187+ DxTextAreaModule ,
188+ DxFormModule ,
189+ DxDateBoxModule ,
190+ DxButtonModule ,
34191 ] ,
35192 declarations : [ AppComponent ] ,
36193 bootstrap : [ AppComponent ] ,
0 commit comments