Add functionality
[usecase-ui.git] / usecaseui-portal / src / app / views / maas / use / use-application.component.ts
1 import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '@angular/core';
2 import { NzMessageService } from 'ng-zorro-antd';
3 import { SSE } from "sse.js";
4 import { ActivatedRoute } from '@angular/router';
5 import { MaasApi } from '@src/app/api/maas.api';
6 import { TranslateService } from '@ngx-translate/core';
7 import { MaasService } from '../maas-service.service';
8 export type StatusEnum = 'typing' | 'finished';
9 export type Chat = { question: string, answer: string, questionId: string, status: StatusEnum };
10 @Component({
11   selector: 'app-use-application',
12   templateUrl: './use-application.component.html',
13   styleUrls: ['./use-application.component.less']
14 })
15 export class UseApplicationComponent implements OnInit {
16   question: string;
17   communicationMessage: string;
18   chatHistory: Chat[] = [];
19   apiUrl = '/api/usecaseui-llm-adaptation/v1/application/chat';
20   queryParams: { id?: string; name?: string } = {};
21   selectedName: string | null = null;
22   options: Array<{ nzValue: string, nzLabel: string }> = [];
23   send = this.translate.instant('maas.send');
24   private currentSSE: SSE | null = null;
25   isGeneratingAnswer: boolean = false;
26   stopGenerating = this.translate.instant('maas.stopGenerating');
27   questionId = '';
28   constructor(
29     private message: NzMessageService,
30     private route: ActivatedRoute,
31     private myhttp: MaasApi,
32     private translate: TranslateService,
33     private maasService: MaasService
34   ) { }
35
36   async ngOnInit() {
37     await this.fetchAllApplication();
38     this.route.queryParams.subscribe(params => {
39       this.queryParams = params;
40       this.selectedName = this.queryParams.id || this.selectedName;
41     });
42   }
43   
44   close() {
45     if (this.currentSSE) {
46       this.currentSSE.close();
47     }
48   }
49
50   doAction() {
51     if (this.isGeneratingAnswer) {
52       this.close();
53       this.chatHistory.forEach(item => {item.status = 'finished'});
54       this.isGeneratingAnswer = false;
55     } else {
56       this.submitQuestion();
57     }
58   }
59
60   submitQuestion() {
61     if (!this.question) {
62       return;
63     }
64     this.isGeneratingAnswer = true;
65     const chatParam = {
66       applicationId: this.selectedName,
67       question: this.question,
68       questionId: this.maasService.generateUniqueId()
69     };
70     this.currentSSE = new SSE(this.apiUrl, { headers: { 'Content-Type': 'application/json' }, payload: JSON.stringify(chatParam), method: 'POST' });
71     const questionId = chatParam.questionId;
72     this.chatHistory.push({ question: chatParam.question, questionId: chatParam.questionId, answer: '', status: 'typing' });
73     this.currentSSE.addEventListener('message', (event) => {
74       const chat = this.chatHistory.find(chatItem => chatItem.questionId === questionId);
75       if (chat) {
76         if (['[DONE]', 'Network Error'].includes(event.data)) {
77           chat.status = 'finished';
78           this.isGeneratingAnswer = false;
79           if (event.data === 'Network Error') {
80             this.updateAnswer(event, chat);
81           }
82           this.close();
83         } else {
84           this.updateAnswer(event, chat);
85         }
86       }
87     });
88     this.currentSSE.addEventListener('error', () => {
89       this.currentSSE = null;
90       this.isGeneratingAnswer = false;
91     });
92     this.currentSSE.addEventListener('close', () => {
93       this.currentSSE = null;
94       this.isGeneratingAnswer = false;
95     });
96     this.question = '';
97   }
98
99   updateAnswer(event: any, chat: Chat): void {
100     chat.answer += event.data.replace(/__SPACE__/g, ' ');
101   }
102
103   async fetchAllApplication(): Promise<void> {
104     try {
105       const data = await this.myhttp.getAllApplication().toPromise();
106       this.options = data.result_body.map(item => ({
107         nzValue: item.applicationId,
108         nzLabel: item.applicationName
109       }));
110       this.selectedName = this.options.length > 0 ? this.options[0].nzValue : '';
111     } catch {
112       this.message.error('Failed to obtain intent data');
113     }
114   }
115
116   async copy(content: string): Promise<void> {
117     try {
118       await (navigator as any).clipboard.writeText(content);
119       this.message.success(this.translate.instant('maas.copy_to_clipboard'));
120     } catch (err) {
121       console.error(this.translate.instant('maas.copy_failed') + ': ', err);
122     }
123   }
124
125   deleteQuestion(questionId: string): void {
126     this.chatHistory = this.chatHistory.filter(item => item.questionId !== questionId);
127   }
128 }