0ee40d7ba150243f9c162715072b705681b51aa8
[usecase-ui.git] /
1 import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
2 import { NzMessageService } from "ng-zorro-antd";
3 import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
4 import { MaasApi } from '@src/app/api/maas.api';
5 import { KnowledgeBase, MaaSPlatform, ModelInformation, Operators } from '../../knowledge-base-management/knowledge-base.type';
6 import { Subject } from 'rxjs';
7 import { debounceTime } from 'rxjs/operators';
8 import { Application } from '../application.type';
9
10 @Component({
11   selector: 'app-create-application-management',
12   templateUrl: './create-application-management.component.html',
13   styleUrls: ['./create-application-management.component.less']
14 })
15 export class CreateApplicationManagementComponent implements OnInit {
16   @Input() applicationId: string;
17   title = 'Add Application';
18   isEdit_ = false;
19   @Input()
20   set isEdit(v: boolean) {
21     if (v) {
22       this.title = 'Edit Application';
23     } else {
24       this.title = 'Add Application';
25     }
26     this.isEdit_ = v;
27   }
28
29   get isEdit() {
30     return this.isEdit_;
31   }
32   validateForm: FormGroup;
33   @Input() showModal: boolean;
34   @Output() modalOpreation = new EventEmitter();
35   operators: Operators[] = [];
36   filteredPlatforms: MaaSPlatform[] = [];
37   filteredModels: ModelInformation[] = [];
38   knowledgeBases: KnowledgeBase[] = [];
39   temperature = 3;
40   top_p = 3;
41   private submitSubject = new Subject<void>();
42   @ViewChild('myTextarea') myTextarea: ElementRef;
43   @ViewChild('charCount') charCount: ElementRef;
44   @Input() existedNames: string[] = [];
45   application: Application;
46
47   constructor(
48     private myhttp: MaasApi,
49     private message: NzMessageService,
50     private fb: FormBuilder
51   ) { }
52
53   async ngOnInit() {
54     this.initFormData();
55     await this.fetchOperators();
56     if (this.isEdit) {
57       await this.fetchApplication();
58     }
59     this.submitSubject.pipe(debounceTime(3000)).subscribe(() => this.executeSubmit());
60   }
61
62   async fetchApplication(): Promise<void> {
63     try {
64       const response = await this.myhttp.getApplicationById(this.applicationId).toPromise();
65       if (response.result_header.result_code !== 200) {
66         this.message.error('get application error');
67         return;
68       }
69       this.application = response.result_body;
70
71       this.validateForm.patchValue({
72         name: this.application.applicationName,
73         description: this.application.applicationDescription,
74         applicationType: this.application.applicationType,
75         selectedOperator: this.operators.find(i => i.operatorId === this.application.operatorId),
76         selectedPlatform: this.application.maaSPlatformId,
77         selectedModel: this.application.largeModelId,
78         selectKnowledgeBase: this.application.knowledgeBaseId,
79         prompt: this.application.prompt,
80         openingRemarks: this.application.openingRemarks,
81         temperature: this.application.temperature,
82         top_p: this.application.top_p,
83         temperatureSlider: this.application.temperature,
84         top_pSlider: this.application.top_p
85       });
86     } catch (error) {
87       this.message.error('Failed to obtain knowledge base data');
88     }
89   }
90
91   nameDuplicateValidator = (control: FormControl): { [s: string]: boolean } => {
92     if (!control.value) {
93       return { required: true };
94     } else if (this.existedNames.includes(control.value)) {
95       return { duplicated: true, error: true };
96     }
97   }
98
99   initFormData() {
100     this.validateForm = this.fb.group({
101       name: this.isEdit ? [null, [Validators.required]] : [null, [Validators.required, this.nameDuplicateValidator]],
102       description: [null],
103       applicationType: [null, [Validators.required]],
104       selectedOperator: [null, [Validators.required]],
105       selectedPlatform: [null, [Validators.required]],
106       selectedModel: [null, [Validators.required]],
107       selectKnowledgeBase: [null, [Validators.required]],
108       prompt: [null, [Validators.required, Validators.minLength(20), Validators.maxLength(1000)]],
109       openingRemarks: [null, [Validators.required]],
110       temperature: [3, [Validators.required]],
111       temperatureSlider: [3],
112       top_p: [3, [Validators.required]],
113       top_pSlider: [3]
114     });
115   }
116
117   async fetchOperators(): Promise<void> {
118     try {
119       const response = await this.myhttp.getOperators().toPromise();
120       this.operators = response.result_body;
121     } catch (error) {
122       this.message.error('Failed to fetch operators');
123     }
124   }
125
126   handleOperatorChange(value: Operators): void {
127     if (value) {
128       this.filteredPlatforms = value.maaSPlatformList;
129     } else {
130       this.filteredPlatforms = [];
131     }
132     this.validateForm.get('selectedPlatform').setValue(null);
133     this.validateForm.get('selectedModel').setValue(null);
134     this.validateForm.get('selectKnowledgeBase').setValue(null);
135   }
136
137   handleMaasChange(maaSPlatformId: string): void {
138     if (maaSPlatformId) {
139       const filteredPlatformsByMaas = this.filteredPlatforms.find(i => i.maaSPlatformId === maaSPlatformId)
140       this.filteredModels = filteredPlatformsByMaas ? filteredPlatformsByMaas.modelList : [];
141       this.fetchKnowledgeBase(maaSPlatformId);
142     } else {
143       this.filteredModels = [];
144     }
145     this.validateForm.get('selectedModel').setValue(null);
146     this.validateForm.get('selectKnowledgeBase').setValue(null);
147   }
148
149   fetchKnowledgeBase(maaSPlatformId: string): void {
150     this.myhttp.fetchKnowledgeBaseByMaasId(maaSPlatformId).subscribe(
151       (response) => {
152         this.knowledgeBases = response.result_body;
153       },
154       () => {
155         this.message.error('Failed to fetch knowledge base');
156       }
157     );
158   }
159
160   handleCancel(): void {
161     this.showModal = false;
162     this.modalOpreation.emit({ "cancel": true });
163   }
164
165   handleOk() {
166     this.submitSubject.next();
167   }
168
169   private executeSubmit() {
170     this.submitForm();
171     if (this.validateForm.invalid) {
172       this.showModal = true;
173       return;
174     }
175     const url = this.isEdit ? this.myhttp.url.updateApplication : this.myhttp.url.createApplicationUrl;
176     this.myhttp.createApplication(url, this.constructBody()).subscribe(
177       (response) => {
178         if (response.result_header.result_code === 200) {
179           this.showModal = false;
180           this.modalOpreation.emit({ "cancel": false });
181           this.message.success('Operate successfully');
182         } else {
183           this.message.error(response.result_header.result_message);
184         }
185       },
186       () => {
187         this.showModal = false;
188         this.message.error('Operate failed');
189       }
190     )
191   }
192
193   constructBody() {
194     const filteredPlatformById = this.filteredPlatforms.find(i => i.maaSPlatformId === this.validateForm.value.selectedPlatform);
195     const maaSPlatformName = filteredPlatformById ? filteredPlatformById.maaSPlatformName : '';
196     const filteredModelById = this.filteredModels.find(i => i.modelId === this.validateForm.value.selectedModel);
197     const largeModelName = filteredModelById ? filteredModelById.modelName : '';
198     const filteredKnowledgebaseById = this.knowledgeBases.find(i => i.knowledgeBaseId === this.validateForm.value.selectKnowledgeBase);
199     const knowledgeBaseName = filteredKnowledgebaseById ? filteredKnowledgebaseById.knowledgeBaseName : '';
200
201     const requestBody = {
202       applicationName: this.validateForm.value.name,
203       applicationDescription: this.validateForm.value.description,
204       applicationType: this.validateForm.value.applicationType,
205       operatorName: this.validateForm.value.selectedOperator.operatorName,
206       operatorId: this.validateForm.value.selectedOperator.operatorId,
207       maaSPlatformId: this.validateForm.value.selectedPlatform,
208       maaSPlatformName,
209       knowledgeBaseId: this.validateForm.value.selectKnowledgeBase,
210       knowledgeBaseName,
211       largeModelId: this.validateForm.value.selectedModel,
212       largeModelName,
213       prompt: this.validateForm.value.prompt,
214       temperature: this.validateForm.value.temperature,
215       top_p: this.validateForm.value.top_p,
216       openingRemarks: this.validateForm.value.openingRemarks
217     }
218     if (this.isEdit) {
219       requestBody['applicationId'] = this.applicationId;
220     } 
221     return requestBody;
222   }
223
224   submitForm(): void {
225     for (let i in this.validateForm.controls) {
226       this.validateForm.controls[i].markAsDirty();
227       this.validateForm.controls[i].updateValueAndValidity();
228     }
229   }
230
231   handleTemperatureSliderChange(event: number): void {
232     this.validateForm.controls.temperature.setValue(event);
233   }
234
235   handleTemperatureInputChange(event: number): void {
236     this.validateForm.controls.temperatureSlider.setValue(event);
237   }
238
239   handletoppChange(event: number): void {
240     this.validateForm.controls.top_p.setValue(event);
241   }
242
243   toppSliderChange(event: number): void {
244     this.validateForm.controls.top_p.setValue(event);
245   }
246
247   toppInputChange(event: number): void {
248     this.validateForm.controls.top_pSlider.setValue(event);
249   }
250
251   updateCharCount() {
252     const textarea = this.myTextarea.nativeElement as HTMLTextAreaElement;
253     const charCount = textarea.value.length;
254     const maxLength = textarea.getAttribute('maxlength');
255     this.charCount.nativeElement.innerText = charCount + '/' + maxLength;
256   }
257 }
258