d8f68ad5593e86d6a2e52c89667376ff9456fa4b
[usecase-ui/llm-adaptation.git] /
1 package org.onap.usecaseui.llmadaptation.service.impl;
2
3 import com.alibaba.fastjson2.JSONArray;
4 import com.alibaba.fastjson2.JSONObject;
5 import com.fasterxml.jackson.databind.ObjectMapper;
6 import lombok.extern.slf4j.Slf4j;
7 import org.onap.usecaseui.llmadaptation.bean.Application;
8 import org.onap.usecaseui.llmadaptation.bean.KnowledgeBase;
9 import org.onap.usecaseui.llmadaptation.bean.ResultHeader;
10 import org.onap.usecaseui.llmadaptation.bean.ServiceResult;
11 import org.onap.usecaseui.llmadaptation.bean.fastgpt.CreateDataSetResponse;
12 import org.onap.usecaseui.llmadaptation.bean.fastgpt.application.*;
13 import org.onap.usecaseui.llmadaptation.constant.FastGptConstant;
14 import org.onap.usecaseui.llmadaptation.mapper.FastGptApplicationMapper;
15 import org.onap.usecaseui.llmadaptation.mapper.FastGptDatasetMapper;
16 import org.onap.usecaseui.llmadaptation.service.FastGptApplicationService;
17 import org.onap.usecaseui.llmadaptation.util.TimeUtil;
18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.core.io.ResourceLoader;
20 import org.springframework.stereotype.Service;
21 import org.springframework.util.CollectionUtils;
22 import org.springframework.web.reactive.function.client.WebClient;
23 import reactor.core.publisher.Flux;
24 import reactor.core.publisher.Mono;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.UUID;
31 import java.util.concurrent.atomic.AtomicBoolean;
32
33 import static org.springframework.http.MediaType.APPLICATION_JSON;
34
35 @Slf4j
36 @Service
37 public class FastGptApplicationServiceImpl implements FastGptApplicationService {
38     @Autowired
39     private ResourceLoader resourceLoader;
40
41     @Autowired
42     private FastGptApplicationMapper fastGptApplicationMapper;
43
44     @Autowired
45     private WebClient webClient;
46
47     @Autowired
48     private FastGptDatasetMapper fastGptDatasetMapper;
49
50     private final ObjectMapper objectMapper = new ObjectMapper();
51
52     public Mono<ServiceResult> createApplication(Application application) {
53         try (InputStream inputStream = resourceLoader.getResource(FastGptConstant.CREATE_APP_PARAM_FILE_URL).getInputStream()) {
54             CreateApplicationParam createApplicationParam = objectMapper.readValue(inputStream, CreateApplicationParam.class);
55             createApplicationParam.setName(application.getApplicationName());
56
57             return createApplication(createApplicationParam, application)
58                     .onErrorResume(e -> {
59                         log.error("Error occurred while creating application: {}", e.getMessage());
60                         return Mono.just(new ServiceResult(new ResultHeader(500, "Application creation failed")));
61                     });
62
63         } catch (IOException e) {
64             log.error("Error occurred while reading input file: {}", e.getMessage());
65             return Mono.just(new ServiceResult(new ResultHeader(500, "Failed to read input file")));
66         }
67     }
68
69     private Mono<ServiceResult> createApplication(CreateApplicationParam createApplicationParam, Application application) {
70         return webClient.post()
71                 .uri(FastGptConstant.CREATE_APPLICATION)
72                 .contentType(APPLICATION_JSON)
73                 .header(FastGptConstant.COOKIE, FastGptConstant.COOKIE_VALUE)
74                 .bodyValue(createApplicationParam)
75                 .retrieve()
76                 .bodyToMono(CreateDataSetResponse.class)
77                 .flatMap(response -> {
78                     if (response.getCode() == 200) {
79                         return handleApplicationResponse(response, application);
80                     }
81                     return Mono.just(new ServiceResult(new ResultHeader(500, response.getStatusText())));
82                 });
83     }
84
85     private Mono<ServiceResult> handleApplicationResponse(CreateDataSetResponse createDataSetResponse, Application application) {
86         String data = String.valueOf(createDataSetResponse.getData());
87         application.setApplicationId(data);
88         String url = FastGptConstant.UPDATE_APPLICATION + data;
89         UpdateApplicationParam updateApplicationParam = new UpdateApplicationParam();
90         updateApplicationParam.setAvatar("/imgs/app/avatar/simple.svg");
91         updateApplicationParam.setDefaultPermission(0);
92         updateApplicationParam.setName(application.getApplicationName());
93         updateApplicationParam.setIntro(application.getApplicationDescription());
94
95         return webClient.put()
96                 .uri(url)
97                 .contentType(APPLICATION_JSON)
98                 .header(FastGptConstant.COOKIE, FastGptConstant.COOKIE_VALUE)
99                 .bodyValue(updateApplicationParam)
100                 .retrieve()
101                 .bodyToMono(CreateDataSetResponse.class)
102                 .flatMap(response -> {
103                     if (response.getCode() == 200) {
104                         return publishApplication(application, data);
105                     }
106                     return Mono.just(new ServiceResult(new ResultHeader(500, response.getStatusText())));
107                 });
108     }
109
110     private Mono<ServiceResult> publishApplication(Application application, String data) {
111         try (InputStream inputStream = resourceLoader.getResource(FastGptConstant.PUBLISH_APP_PARAM_FILE_URL).getInputStream()) {
112             PublishApplicationParam publishApplicationParam = objectMapper.readValue(inputStream, PublishApplicationParam.class);
113             publishApplicationParam.setVersionName(TimeUtil.getNowTime());
114             publishApplicationParam.getChatConfig().setWelcomeText(application.getOpeningRemarks());
115             setApplicationParameters(application, publishApplicationParam);
116             String publishUrl = FastGptConstant.PUBLISH_APPLICATION + data;
117
118             return webClient.post()
119                     .uri(publishUrl)
120                     .contentType(APPLICATION_JSON)
121                     .header(FastGptConstant.COOKIE, FastGptConstant.COOKIE_VALUE)
122                     .bodyValue(publishApplicationParam)
123                     .retrieve()
124                     .bodyToMono(CreateDataSetResponse.class)
125                     .flatMap(response -> {
126                         if (response.getCode() == 200) {
127                             fastGptApplicationMapper.insertApplication(application);
128                             return Mono.just(new ServiceResult(new ResultHeader(200, "Application created successfully")));
129                         }
130                         return Mono.just(new ServiceResult(new ResultHeader(500, response.getStatusText())));
131                     });
132         } catch (IOException e) {
133             log.error("Error occurred while reading publish parameters: {}", e.getMessage());
134             return Mono.just(new ServiceResult(new ResultHeader(500, "Failed to read publish parameters")));
135         }
136     }
137
138     private void setApplicationParameters(Application application, PublishApplicationParam publishApplicationParam) {
139         publishApplicationParam.getNodes().forEach(node -> {
140             if ("chatNode".equals(node.getFlowNodeType())) {
141                 node.getInputs().forEach(input -> {
142                     switch (input.getKey()) {
143                         case "temperature":
144                             input.setValue(application.getTemperature());
145                             break;
146                         case "systemPrompt":
147                             input.setValue(application.getPrompt());
148                             break;
149                         case "model":
150                             log.info(application.getLargeModelName());
151                             input.setValue(application.getLargeModelName());
152                             break;
153                     }
154                 });
155             } else if ("datasetSearchNode".equals(node.getFlowNodeType())) {
156                 node.getInputs().forEach(input -> {
157                     if ("datasets".equals(input.getKey())) {
158                         JSONObject jsonObject = new JSONObject();
159                         jsonObject.put("datasetId", application.getKnowledgeBaseId());
160                         List<JSONObject> list = new ArrayList<>();
161                         list.add(jsonObject);
162                         input.setValue(list);
163                     }
164                 });
165             }
166         });
167     }
168
169     public Flux<String> chat(JSONObject question) {
170         log.info(JSONObject.toJSONString(question));
171         ChatParam chatParam = new ChatParam();
172         chatParam.setAppId(question.getString("applicationId"));
173         chatParam.setStream(true);
174         chatParam.setDetail(true);
175         chatParam.setChatId(UUID.randomUUID().toString());
176         chatParam.setResponseChatItemId(UUID.randomUUID().toString());
177         JSONObject time = new JSONObject();
178         time.put("cTime", TimeUtil.getFormattedDateTime());
179         chatParam.setVariables(time);
180         Message message = new Message();
181         message.setContent(question.getString("question"));
182         message.setDataId(UUID.randomUUID().toString());
183         message.setRole("user");
184         List<Message> messages = new ArrayList<>();
185         messages.add(message);
186         chatParam.setMessages(messages);
187         AtomicBoolean isDone = new AtomicBoolean(false);
188         return webClient.post()
189                 .uri(FastGptConstant.APPLICATION_CHAT_URL)
190                 .contentType(APPLICATION_JSON)
191                 .header(FastGptConstant.COOKIE, FastGptConstant.COOKIE_VALUE)
192                 .bodyValue(chatParam)
193                 .retrieve()
194                 .bodyToFlux(String.class).flatMap(response -> parseAndTransform(response, isDone))
195                 .onErrorResume(throwable -> {
196                     log.error("An error occurred {}", throwable.getMessage());
197                     return Flux.just("Network Error");
198                 });
199     }
200
201     private Flux<String> parseAndTransform(String param, AtomicBoolean isDone) {
202         if (isDone.get()) {
203             return Flux.empty();
204         }
205         JSONObject jsonObject = JSONObject.parseObject(param);
206         if (!jsonObject.containsKey("choices")) {
207             return Flux.empty();
208         }
209         JSONArray choices = jsonObject.getJSONArray("choices");
210         JSONObject choice = choices.getJSONObject(0);
211         if ("stop".equals(choice.getString("finish_reason"))) {
212             isDone.set(true);
213             return Flux.empty();
214         }
215         String string = choice.getJSONObject("delta").getString("content");
216         isDone.set(false);
217         string = string.replace(" ", "__SPACE__");
218         return Flux.just(string);
219     }
220
221     public Mono<ServiceResult> removeApplication(String applicationId) {
222         String url = FastGptConstant.DELETE_APPLICATION + applicationId;
223
224         return webClient.delete()
225                 .uri(url)
226                 .header(FastGptConstant.COOKIE, FastGptConstant.COOKIE_VALUE)
227                 .retrieve()
228                 .bodyToMono(CreateDataSetResponse.class)
229                 .flatMap(response -> {
230                     if (response.getCode() == 200) {
231                         return Mono.fromRunnable(() -> {
232                             try {
233                                 fastGptApplicationMapper.deleteApplicationById(applicationId);
234                             } catch (Exception dbException) {
235                                 throw new RuntimeException("Database operation failed", dbException); // 抛出新异常
236                             }
237                         }).then(Mono.just(new ServiceResult(new ResultHeader(200, "delete success"))));
238                     } else {
239                         return Mono.just(new ServiceResult(new ResultHeader(500, response.getStatusText())));
240                     }
241                 })
242                 .onErrorResume(e -> {
243                     log.error("Error occurred while delete dataset: {}", e.getMessage());
244                     return Mono.just(new ServiceResult(new ResultHeader(500, "delete failed")));
245                 });
246     }
247
248     public ServiceResult getApplications() {
249         List<Application> allApplication = fastGptApplicationMapper.getAllApplication();
250         if (CollectionUtils.isEmpty(allApplication)) {
251             return new ServiceResult(new ResultHeader(200, "no application"), allApplication);
252         }
253         allApplication.forEach(application -> {
254             KnowledgeBase knowledgeBaseRecordById = fastGptDatasetMapper.getKnowledgeBaseRecordById(application.getKnowledgeBaseId());
255             if (knowledgeBaseRecordById != null) {
256                 application.setOperatorId(knowledgeBaseRecordById.getOperatorId());
257                 application.setOperatorName(knowledgeBaseRecordById.getOperatorName());
258                 application.setMaaSPlatformId(knowledgeBaseRecordById.getMaaSPlatformId());
259                 application.setMaaSPlatformName(knowledgeBaseRecordById.getMaaSPlatformName());
260                 application.setKnowledgeBaseName(knowledgeBaseRecordById.getKnowledgeBaseName());
261             }
262         });
263         return new ServiceResult(new ResultHeader(200, "success"), allApplication);
264     }
265
266     public ServiceResult getApplicationById(String applicationId) {
267         Application application = fastGptApplicationMapper.getApplicationById(applicationId);
268         if (application == null) {
269             return new ServiceResult(new ResultHeader(200, "no application"), application);
270         }
271         KnowledgeBase knowledgeBaseRecordById = fastGptDatasetMapper.getKnowledgeBaseRecordById(application.getKnowledgeBaseId());
272         application.setOperatorId(knowledgeBaseRecordById.getOperatorId());
273         application.setOperatorName(knowledgeBaseRecordById.getOperatorName());
274         application.setMaaSPlatformId(knowledgeBaseRecordById.getMaaSPlatformId());
275         application.setMaaSPlatformName(knowledgeBaseRecordById.getMaaSPlatformName());
276         application.setKnowledgeBaseName(knowledgeBaseRecordById.getKnowledgeBaseName());
277         return new ServiceResult(new ResultHeader(200, "success"), application);
278     }
279 }