TakaiAiServiceImpl.java 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. package com.takai.ai.service.impl;
  2. import com.alibaba.fastjson2.JSON;
  3. import com.alibaba.fastjson2.JSONArray;
  4. import com.alibaba.fastjson2.JSONObject;
  5. import com.takai.ai.domain.TakaiSysOss;
  6. import com.takai.ai.domain.dto.TakaiDialogDetailReqDTO;
  7. import com.takai.ai.domain.entity.*;
  8. import com.takai.ai.mapper.*;
  9. import com.takai.ai.service.ITakaiAiService;
  10. import com.takai.ai.utils.MinioUtil;
  11. import com.takai.ai.utils.SnowflakeDigitGenerator;
  12. import com.takai.common.annotation.DataSource;
  13. import com.takai.common.config.DeepseekConfig;
  14. import com.takai.common.core.redis.RedisCache;
  15. import com.takai.common.enums.DataSourceType;
  16. import com.takai.ai.domain.dto.TakaiDialogReqDTO;
  17. import com.takai.ai.domain.dto.TakaiDialogRespDTO;
  18. import com.takai.ai.domain.dto.TakaiQuestionDTO;
  19. import com.takai.common.utils.StringUtils;
  20. import com.takai.common.utils.uuid.IdUtils;
  21. import lombok.extern.slf4j.Slf4j;
  22. import okhttp3.*;
  23. import okhttp3.sse.EventSource;
  24. import okhttp3.sse.EventSourceListener;
  25. import okhttp3.sse.EventSources;
  26. import org.slf4j.Logger;
  27. import org.slf4j.LoggerFactory;
  28. import org.springframework.beans.factory.annotation.Autowired;
  29. import org.springframework.data.redis.core.RedisTemplate;
  30. import org.springframework.stereotype.Service;
  31. import org.springframework.web.multipart.MultipartFile;
  32. import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  33. import javax.validation.constraints.NotNull;
  34. import java.io.IOException;
  35. import java.time.LocalDate;
  36. import java.time.LocalDateTime;
  37. import java.time.temporal.ChronoUnit;
  38. import java.util.*;
  39. import java.util.concurrent.TimeUnit;
  40. import java.util.stream.Collectors;
  41. /**
  42. * 高井 业务层处理
  43. *
  44. * @author takai
  45. */
  46. @Slf4j
  47. @Service
  48. @DataSource(DataSourceType.MASTER)
  49. public class TakaiAiServiceImpl implements ITakaiAiService {
  50. private static final Logger logger = LoggerFactory.getLogger(TakaiAiServiceImpl.class);
  51. @Autowired
  52. private TakaiDialogMapper takaiDialogMapper;
  53. @Autowired
  54. private TakaiApplicationMapper takaiApplicationMapper;
  55. @Autowired
  56. private TakaiQuestionMapper takaiQuestionMapper;
  57. @Autowired
  58. private TakaiKnowledgeMapper takaiKnowledgeMapper;
  59. @Autowired
  60. private TakaiDocumentMapper takaiDocumentMapper;
  61. @Autowired
  62. private TakaiSysOssConfigMapper takaiSysOssConfigMapper;
  63. @Autowired
  64. private TakaiSysOssMapper takaiSysOssMapper;
  65. @Autowired
  66. private MinioUtil minioUtil;
  67. @Autowired
  68. private TakaiDocumentSettingsMapper takaiDocumentSettingsMapper;
  69. @Autowired
  70. private DeepseekConfig deepseekConfig;
  71. @Autowired
  72. private TakaiAppInfoMapper takaiAppInfoMapper;
  73. @Autowired
  74. private TakaiMediaReplacementMapper takaiMediaReplacementMapper;
  75. @Autowired
  76. private RedisCache redisCache;
  77. @Autowired
  78. public RedisTemplate redisTemplate;
  79. public static final String START_SIGN = "【";
  80. public static final String END_SIGN = "】";
  81. public static final String SYMBOL = "【示意图序号";
  82. public static final String USER_STR = "user";
  83. public static final String TODAY = "今天";
  84. public static final String BEFOR = "天前";
  85. @Override
  86. public void initDeepseekInfo() {
  87. //获取应用列表
  88. // List<TakaiApplication> appList = takaiApplicationMapper.selectApplicationList(null);
  89. setRedisCache(null);
  90. }
  91. private void setRedisCache(String knowledgeId) {
  92. //获取知识库列表
  93. List<TakaiKnowledge> knowledgeList = null;
  94. if (StringUtils.isEmpty(knowledgeId)) {
  95. knowledgeList = takaiKnowledgeMapper.selectKnowledgeList(null);
  96. } else {
  97. knowledgeList = takaiKnowledgeMapper.selectKnowledgeList(TakaiKnowledge.builder().knowledgeId(knowledgeId).build());
  98. }
  99. //获取知识列表
  100. if (!knowledgeList.isEmpty()) {
  101. for (TakaiKnowledge bmKnowledge : knowledgeList) {
  102. TakaiDocument conditon = TakaiDocument.builder().knowledgeId(bmKnowledge.getKnowledgeId()).build();
  103. List<TakaiDocument> documentList = takaiDocumentMapper.selectDocumentList(conditon);
  104. if (!documentList.isEmpty()) {
  105. for (TakaiDocument bmDocument : documentList) {
  106. //获取知识图片列表
  107. TakaiMediaReplacement conditonR = TakaiMediaReplacement.builder().documentId(bmDocument.getDocumentId()).build();
  108. List<TakaiMediaReplacement> imageList = takaiMediaReplacementMapper.selectMediaList(conditonR);
  109. if (!imageList.isEmpty()) {
  110. for (TakaiMediaReplacement image : imageList) {
  111. redisCache.setCacheObject(image.getOriginText(), image.getMediaUrl());
  112. }
  113. }
  114. }
  115. }
  116. }
  117. }
  118. }
  119. @Override
  120. public SseEmitter sseInvoke(TakaiSseInfoParams sseParams) {
  121. TakaiApplication appInfo = takaiApplicationMapper.selectTargetApplication(TakaiApplication.builder().appId(sseParams.getAppId()).build());
  122. if (appInfo != null) {
  123. TakaiKnowledge knowledge = takaiKnowledgeMapper.selectTargetKnowledge(TakaiKnowledge.builder().knowledgeId(appInfo.getKnowledgeIds()).build());
  124. if (knowledge != null) {
  125. SseEmitter sseEmitter = new SseEmitter(0L);
  126. String url = deepseekConfig.getBaseurl() + deepseekConfig.getChat();
  127. TakaiAppInfo info = takaiAppInfoMapper.selectAppInfoByAppId(sseParams.getAppId());
  128. JSONObject json = JSONObject.parseObject(info.getAppInfo());
  129. String query = sseParams.getPrompt().get(sseParams.getPrompt().size() - 1).getContent();
  130. log.info("deepseek聊天请求参数:" + query);
  131. json.put("query", query);
  132. json.put("embeddingId", knowledge.getEmbeddingId());
  133. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), json.toJSONString());
  134. Request request = buildPostRequest(url, requestBody);
  135. // 使用EventSourceListener处理来自服务器的SSE事件
  136. EventSourceListener listener = new EventSourceListener() {
  137. private String preData = "";
  138. //图片识别
  139. private String symbolData = "";
  140. @Override
  141. public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
  142. log.info("deepseek Connection opened. Headers: {}", response.headers());
  143. log.info("deepseek Request URL: {}", response.request().url());
  144. }
  145. @Override
  146. public void onClosed(@NotNull EventSource eventSource) {
  147. log.info("deepseek Connection closed.");
  148. sseEmitter.complete();
  149. }
  150. @Override
  151. public void onEvent(@NotNull EventSource eventSource, String id, String type, @NotNull String data) {
  152. if (!StringUtils.isEmpty(data)) {
  153. String newData = data.substring(preData.length());
  154. if (com.takai.common.utils.StringUtils.isNotEmpty(type) && "finish".equals(type)) {
  155. logger.info("deepseek聊天结束", newData);
  156. }
  157. logger.info("deepseek聊天返回消息:" + data);
  158. preData = data;
  159. if (newData.indexOf(START_SIGN) > -1 || symbolData.length() > 0) {
  160. symbolData = symbolData + newData;
  161. //接收到了完整的图片标识
  162. if (newData.indexOf(END_SIGN) > -1) {
  163. //是图片
  164. if (symbolData.indexOf(SYMBOL) > -1) {
  165. //获取完整Key
  166. int startPos = symbolData.indexOf(START_SIGN);
  167. int endPos = symbolData.indexOf(END_SIGN) + 1;
  168. String key = symbolData.substring(startPos, endPos);
  169. String url = redisCache.getCacheObject(key);
  170. if (org.springframework.util.StringUtils.hasText(url)) {
  171. //匹配markdown图片格式
  172. symbolData = symbolData.replace(key, "![](" + url + ")");
  173. }
  174. }
  175. JSONObject json = new JSONObject();
  176. json.put("id", id);
  177. json.put("event", "add");
  178. json.put("data", symbolData);
  179. log.info("deepseek返回信息:" + json);
  180. symbolData = "";
  181. send(sseEmitter, json);
  182. }
  183. } else {
  184. JSONObject json = new JSONObject();
  185. json.put("id", id);
  186. json.put("event", type);
  187. json.put("data", newData);
  188. log.info("deepseek返回信息:" + json);
  189. send(sseEmitter, json);
  190. }
  191. }
  192. }
  193. @Override
  194. public void onFailure(@NotNull EventSource eventSource, Throwable t, Response response) {
  195. if (response != null) {
  196. log.error("deepseek Connection failed. Response code: {}, message: {}, body: {}",
  197. response.code(), response.message(), response.body() != null ? response.body().toString() : "null");
  198. } else {
  199. log.error("deepseek Connection failed with no response", t);
  200. }
  201. sseEmitter.completeWithError(t);
  202. }
  203. private void send(SseEmitter sseEmitter, Object obj) {
  204. try {
  205. sseEmitter.send(obj);
  206. } catch (IOException e) {
  207. log.error("deepseek 推送数据失败", e);
  208. }
  209. }
  210. };
  211. OkHttpClient client = buildOkHttpClient();
  212. EventSource.Factory factory = EventSources.createFactory(client);
  213. final EventSource eventSources = factory.newEventSource(request, listener);
  214. // 客户端主动关闭连接
  215. sseEmitter.onCompletion(() -> {
  216. logger.info("deepseek客户端主动关闭连接 -- SSE 连接关闭");
  217. });
  218. // 超时回调
  219. sseEmitter.onTimeout(() -> {
  220. logger.info("deepseek客户端连接超时 -- SSE 连接关闭");
  221. if(eventSources != null) {
  222. logger.info("deepseek超时回调 -- 成功关闭SSE连接 ");
  223. eventSources.cancel();
  224. }
  225. });
  226. // 错误回调
  227. sseEmitter.onError(e -> {
  228. logger.info("deepseek客户端回调失败 -- SSE 连接关闭");
  229. if(eventSources != null) {
  230. logger.info("deepseek错误回调 -- 成功关闭SSE连接 ");
  231. eventSources.cancel();
  232. }
  233. });
  234. return sseEmitter;
  235. }
  236. }
  237. return null;
  238. }
  239. @Override
  240. public List<String> asyncCompletions(TakaiCompletionsParams params) {
  241. List<String> list = new ArrayList<>();
  242. TakaiApplication vo = takaiApplicationMapper.selectTargetApplication(TakaiApplication.builder().appId(params.getAppId()).build());
  243. if (vo != null) {
  244. TakaiPromptInfo info = new TakaiPromptInfo();
  245. info.setContent(deepseekConfig.getPrompt());
  246. info.setRole("user");
  247. params.getMessages().add(info);
  248. JSONObject jsonObject = new JSONObject();
  249. jsonObject.put("model", vo.getModel());
  250. jsonObject.put("messages", params.getMessages());
  251. JSONObject result = getasyncCompletions(jsonObject);
  252. if (result != null && result.getInteger("code") == 200) {
  253. JSONArray array = result.getJSONArray("data");
  254. list.addAll(array.toJavaList(String.class));
  255. }
  256. }
  257. return list;
  258. }
  259. private JSONObject getasyncCompletions(JSONObject jsonObject) {
  260. String url = deepseekConfig.getBaseurl() + deepseekConfig.getAsyncCompletions();
  261. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toJSONString());
  262. Request request = buildPostRequest(url, requestBody);
  263. OkHttpClient client = buildOkHttpClient();
  264. try {
  265. Response response = client.newCall(request).execute();
  266. if (response.isSuccessful()) {
  267. String body = response.body().string();
  268. if (isJsonObject(body)) {
  269. return JSON.parseObject(body);
  270. }
  271. }
  272. } catch (IOException e) {
  273. log.info("deepseek Request URL: {}", e.getMessage());
  274. }
  275. return null;
  276. }
  277. @Override
  278. public List<TakaiDialogRespDTO> getDialogDetail(String dialogId) {
  279. List<TakaiDialogRespDTO> detail = takaiDialogMapper.selectDialogDetail(dialogId);
  280. return detail;
  281. }
  282. @Override
  283. public void saveDialog(TakaiDialogReqDTO dialogReqDTO) {
  284. String dialogId = null;
  285. TakaiDialogRespDTO dialogVo = null;
  286. if (com.takai.common.utils.StringUtils.isNotEmpty(dialogReqDTO.getId())) {
  287. dialogVo = takaiDialogMapper.selectDialogById(dialogReqDTO.getId());
  288. }
  289. if (dialogVo == null) {
  290. takaiDialogMapper.insertDialog(dialogReqDTO);
  291. dialogId = dialogReqDTO.getId();
  292. } else {
  293. dialogId = dialogReqDTO.getId();
  294. }
  295. for (TakaiDialogDetailReqDTO dto : dialogReqDTO.getMessages()) {
  296. dto.setDialogId(dialogId);
  297. TakaiDialogRespDTO detail = takaiDialogMapper.selectDialogDetailById(dto.getId());
  298. if (detail == null) {
  299. takaiDialogMapper.insertDialogDetail(dto);
  300. }
  301. }
  302. }
  303. @Override
  304. public List<Object> getDialogList(String appId) {
  305. List<TakaiDialogRespDTO> dialogRespDTOS = takaiDialogMapper.selectDialogList(appId);
  306. //当前日期
  307. LocalDate today = LocalDate.now();
  308. //根据时间分组降序排序
  309. NavigableMap<LocalDateTime, List<TakaiDialogRespDTO>> groupList = dialogRespDTOS.stream().collect(Collectors.groupingBy(TakaiDialogRespDTO::getCreate_time, TreeMap::new, Collectors.toList())).descendingMap();
  310. List<Object> obj = new ArrayList();
  311. if (!groupList.isEmpty()) {
  312. for (Map.Entry<LocalDateTime, List<TakaiDialogRespDTO>> entry : groupList.entrySet()) {
  313. // 对比两个时间相差多少天
  314. long daysBetween = ChronoUnit.DAYS.between(today, entry.getKey());
  315. Map<String, Object> m = new HashMap();
  316. m.put("key", System.nanoTime());
  317. m.put("type", "group");
  318. if (daysBetween == 0l) {
  319. m.put("label", TODAY);
  320. m.put("children", setValue(entry.getValue()));
  321. obj.add(m);
  322. } else {
  323. m.put("label", -daysBetween + BEFOR);
  324. m.put("children", setValue(entry.getValue()));
  325. obj.add(m);
  326. }
  327. }
  328. }
  329. return obj;
  330. }
  331. @Override
  332. public void DelDialogDetail(String id) {
  333. int result = takaiDialogMapper.delDialog(id);
  334. if (result > 0) {
  335. takaiDialogMapper.delDialogDetail(id);
  336. }
  337. }
  338. @Override
  339. public void updateDialog(TakaiDialogReqDTO dialogReqDTO) {
  340. takaiDialogMapper.updateDialog(dialogReqDTO);
  341. }
  342. @Override
  343. public List<TakaiDialogRespDTO> exportExcel(String dialogId) {
  344. return takaiDialogMapper.selectDialogExport(dialogId);
  345. }
  346. @Override
  347. public int createKnowledge(TakaiKnowledgeParams knowledge) {
  348. SnowflakeDigitGenerator snowflakeDigitGenerator = new SnowflakeDigitGenerator(1, 1);
  349. long knowledgeId = snowflakeDigitGenerator.nextId();
  350. String url = deepseekConfig.getBaseurl() + deepseekConfig.getCreateKnowledge();
  351. JSONObject jsonObject = new JSONObject();
  352. jsonObject.put("knowledge_id", "a" + knowledgeId);
  353. jsonObject.put("embedding_id", knowledge.getEmbeddingId());
  354. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toJSONString());
  355. Request request = buildPostRequest(url, requestBody);
  356. OkHttpClient client = buildOkHttpClient();
  357. try {
  358. Response response = client.newCall(request).execute();
  359. if (response.isSuccessful()) {
  360. String body = response.body().string();
  361. JSONObject obj = JSON.parseObject(body);
  362. Integer code = obj.getInteger("code");
  363. if (code == 200) {
  364. TakaiKnowledge params = TakaiKnowledge.builder()
  365. .knowledgeId("a" + knowledgeId)
  366. .name(knowledge.getName())
  367. .embeddingId(knowledge.getEmbeddingId())
  368. .description(knowledge.getDescription())
  369. .build();
  370. return takaiKnowledgeMapper.insertKnowledge(params);
  371. }
  372. } else {
  373. logger.error("创建知识库调用python接口失败,返回状态码:{}", response.code());
  374. }
  375. } catch (IOException e) {
  376. logger.error("创建知识库调用python接口失败", e.getMessage());
  377. }
  378. return 0;
  379. }
  380. @Override
  381. public int updateKnowledge(TakaiKnowledgeParams knowledge, String knowledgeId) {
  382. TakaiKnowledge params = TakaiKnowledge.builder().knowledgeId(knowledgeId)
  383. .name(knowledge.getName())
  384. .description(knowledge.getDescription())
  385. .embeddingId(knowledge.getEmbeddingId())
  386. .build();
  387. return takaiKnowledgeMapper.updateKnowledge(params);
  388. }
  389. @Override
  390. public TakaiKnowledge detailKnowledge(String knowledgeId) {
  391. TakaiKnowledge vo = TakaiKnowledge.builder().knowledgeId(knowledgeId).build();
  392. return takaiKnowledgeMapper.selectTargetKnowledge(vo);
  393. }
  394. @Override
  395. public int delKnowledge(String knowledgeId) {
  396. String url = deepseekConfig.getBaseurl() + deepseekConfig.getDeleteKnowledge() + "/" + knowledgeId;
  397. Request request = buildDeleteRequest(url);
  398. OkHttpClient client = buildOkHttpClient();
  399. Response response = null;
  400. try {
  401. response = client.newCall(request).execute();
  402. if (response.isSuccessful()) {
  403. String body = response.body().string();
  404. JSONObject obj = JSON.parseObject(body);
  405. Integer code = obj.getInteger("code");
  406. if (code == 200) {
  407. // TakaiKnowledge info = takaiKnowledgeMapper.selectTargetKnowledge(TakaiKnowledge.builder().knowledgeId(knowledgeId).build());
  408. int knowledgeInt = takaiKnowledgeMapper.delKnowledge(knowledgeId);
  409. if (knowledgeInt > 0) {
  410. takaiDocumentMapper.delDocumentByKnowledgeId(knowledgeId);
  411. takaiDocumentSettingsMapper.deleteDocumentSettingsByKnowledgeId(knowledgeId);
  412. }
  413. return knowledgeInt;
  414. }
  415. }
  416. } catch (IOException e) {
  417. logger.error("删除知识库调用python接口失败", e.getMessage());
  418. }
  419. return 0;
  420. }
  421. @Override
  422. public int uploadDocument(MultipartFile[] files, String knowledgeId) {
  423. List<TakaiSysOss> result = null;
  424. try {
  425. result = minioUtil.uploadMultiple(files);
  426. } catch (Exception e) {
  427. logger.error("上传文件失败", e.getMessage());
  428. }
  429. if (result != null && result.size() > 0) {
  430. List<UploadDocumentParams> params = new ArrayList<>();
  431. for (int i = 0; i<result.size(); i++) {
  432. SnowflakeDigitGenerator documentIdGenerator = new SnowflakeDigitGenerator(i, i);
  433. long documentId = documentIdGenerator.nextId();
  434. UploadDocumentParams param = new UploadDocumentParams();
  435. param.setDocument_id("a" + documentId);
  436. param.setName(result.get(i).getOriginalName());
  437. param.setUrl(result.get(i).getUrl());
  438. params.add(param);
  439. }
  440. TakaiDocumentSettings settings = new TakaiDocumentSettings();
  441. settings.setKnowledgeId(knowledgeId);
  442. JSONObject jsonObject = analysisFile(params, settings, "upload");
  443. if (jsonObject != null && jsonObject.containsKey("code") && jsonObject.getInteger("code") == 200) {
  444. for (UploadDocumentParams vo : params) {
  445. TakaiKnowledge info = takaiKnowledgeMapper.selectTargetKnowledge(TakaiKnowledge.builder().knowledgeId(knowledgeId).build());
  446. if(info != null){
  447. // 更新知识库文件大小,总字符数, 文件总数
  448. JSONObject docInfo = jsonObject.getJSONObject("doc_info");
  449. if(docInfo != null){
  450. Integer fileLen = docInfo.getInteger("file_size");
  451. Integer wordNum = docInfo.getInteger("total_char_len");
  452. Integer sliceTotal = docInfo.getInteger("slice_num");
  453. TakaiKnowledge paramInfo = TakaiKnowledge.builder().knowledgeId(knowledgeId)
  454. .length(info.getLength() == null ? fileLen : info.getLength() + fileLen ) // 文件大小
  455. .wordNum(info.getWordNum() == null ? wordNum : info.getWordNum() + wordNum) // 总字符数
  456. .documentSize(info.getDocumentSize() == null ? sliceTotal : info.getDocumentSize() + sliceTotal) // 文件总数
  457. .build();
  458. takaiKnowledgeMapper.updateKnowledge(paramInfo);
  459. for (TakaiSysOss oss : result) {
  460. // oss保存到数据库
  461. takaiSysOssMapper.insertSysOss(oss);
  462. }
  463. // 保存知识信息
  464. TakaiDocument document = TakaiDocument.builder()
  465. .documentId(vo.getDocument_id())
  466. .knowledgeId(knowledgeId)
  467. .customSeparator(String.format("[\"%s\"", "\\n") + "]")
  468. .sentenceSize("300")
  469. .name(vo.getName())
  470. .url(vo.getUrl())
  471. .sliceTotal(sliceTotal)
  472. .length(fileLen)
  473. .wordNum(wordNum)
  474. .build();
  475. int documentIdInsert = takaiDocumentMapper.insertDocument(document);
  476. if (documentIdInsert > 0) {
  477. // 保存知识设置信息
  478. SnowflakeDigitGenerator snowflakeDigitGenerator = new SnowflakeDigitGenerator(1, 1);
  479. long id = snowflakeDigitGenerator.nextId();
  480. TakaiDocumentSettings dSettings = new TakaiDocumentSettings();
  481. dSettings.setId(String.valueOf(id));
  482. dSettings.setKnowledgeId(knowledgeId);
  483. dSettings.setDocumentId(vo.getDocument_id());
  484. dSettings.setSetSlice("0"); // 默认 按标题段落切片
  485. dSettings.setSetAnalyze("1"); // 默认 图片转换成标识符
  486. dSettings.setSetTable("0"); // 默认 ttable转图片
  487. takaiDocumentSettingsMapper.insertDocumentSettings(dSettings);
  488. }
  489. }
  490. }
  491. }
  492. setRedisCache(knowledgeId);
  493. return 1;
  494. }
  495. }
  496. return 0;
  497. }
  498. @Override
  499. public int updateDocument(TakaiDocumentParams documentParams, String documentId) {
  500. int i = takaiDocumentMapper.updateDocument(TakaiDocument.builder()
  501. .documentId(documentId)
  502. .name(documentParams.getName())
  503. .build());
  504. return i;
  505. }
  506. @Override
  507. public List<TakaiDocument> documentList(TakaiDocumentParams documentParams) {
  508. return takaiDocumentMapper.selectDocumentList(TakaiDocument.builder().knowledgeId(documentParams.getKnowledge_id()).build());
  509. }
  510. @Override
  511. public TakaiDocument documentDetail(String documentId) {
  512. return takaiDocumentMapper.selectTargetDocument(TakaiDocument.builder().documentId(documentId).build());
  513. }
  514. @Override
  515. public int delDocument(String documentId) {
  516. TakaiDocument vo = takaiDocumentMapper.selectTargetDocument(TakaiDocument.builder().documentId(documentId).build());
  517. if(vo != null){
  518. String url = deepseekConfig.getBaseurl() + deepseekConfig.getDeleteDoc() + "/" + documentId + "/" + vo.getKnowledgeId();
  519. Request request = buildDeleteRequest(url);
  520. OkHttpClient client = buildOkHttpClient();
  521. try {
  522. Response response = client.newCall(request).execute();
  523. if (response.isSuccessful()) {
  524. String body = response.body().string();
  525. logger.info("删除知识文件调用python接口返回结果:{}", body);
  526. JSONObject obj = JSON.parseObject(body);
  527. Integer code = obj.getInteger("code");
  528. if (code == 200) {
  529. int i = takaiDocumentMapper.delDocument(documentId);
  530. if(i > 0){
  531. TakaiKnowledge info = takaiKnowledgeMapper.selectTargetKnowledge(TakaiKnowledge.builder().knowledgeId(vo.getKnowledgeId()).build());
  532. if(info != null){
  533. // 更新知识库文件大小,总字符数, 文件总数
  534. TakaiKnowledge paramInfo = TakaiKnowledge.builder().knowledgeId(vo.getKnowledgeId())
  535. .length(vo.getLength() == null ? info.getLength() == null ? 0 : info.getLength() : info.getLength() - vo.getLength()) // 文件大小
  536. .wordNum(vo.getWordNum() == null ? info.getWordNum() == null ? 0 : info.getWordNum() : info.getWordNum() - vo.getWordNum()) // 总字符数
  537. .documentSize(info.getDocumentSize() == null ? 0 : info.getDocumentSize() - 1) // 文件总数
  538. .build();
  539. takaiKnowledgeMapper.updateKnowledge(paramInfo);
  540. }
  541. }
  542. }
  543. }
  544. } catch (IOException e) {
  545. logger.error("删除知识文件调用python接口失败", e.getMessage());
  546. }
  547. }
  548. return 0;
  549. }
  550. @Override
  551. public void uploadUrl(TakaiDocumentObject object) {
  552. }
  553. @Override
  554. public int createApplication(TakaiApplicationParams params) {
  555. SnowflakeDigitGenerator snowflakeDigitGenerator = new SnowflakeDigitGenerator(1, 1);
  556. long appId = snowflakeDigitGenerator.nextId();
  557. TakaiApplication info = TakaiApplication.builder().appId(String.valueOf(appId))
  558. .name(params.getName())
  559. .desc(params.getDesc())
  560. .model(params.getModel())
  561. .knowledgeIds(params.getKnowledge_ids().toString())
  562. .topP(params.getTop_p())
  563. .temperature(params.getTemperature())
  564. .maxToken(params.getMax_token())
  565. .prompt(params.getPrompt())
  566. .knowledgeInfo(params.getKnowledge_info())
  567. .sliceCount(params.getSlice_count())
  568. .build();
  569. int i = takaiApplicationMapper.insertApplication(info);
  570. if (i > 0) {
  571. logger.info("create application success, id:{}, name:{}", appId, params.getName());
  572. TakaiAppInfo appInfo = new TakaiAppInfo();
  573. appInfo.setAppId(String.valueOf(appId));
  574. appInfo.setAppInfo(String.valueOf(JSONObject.from(info).toJSONString()));
  575. takaiAppInfoMapper.insertAppInfo(appInfo);
  576. List<String> list = params.getQuestionList();
  577. if (!list.isEmpty() && list.size() > 0) {
  578. for (String str : list) {
  579. if (org.apache.commons.lang3.StringUtils.isNotBlank(str)) {
  580. String uuid = IdUtils.simpleUUID();
  581. TakaiQuestion question = TakaiQuestion.builder().id(uuid).question(str).appId(String.valueOf(appId)).build();
  582. takaiQuestionMapper.insertQuestion(question);
  583. }
  584. }
  585. }
  586. }
  587. return i;
  588. }
  589. @Override
  590. public int updateApplication(TakaiApplicationParams params, String appId) {
  591. TakaiApplication info = TakaiApplication.builder().appId(appId)
  592. .name(params.getName())
  593. .desc(params.getDesc())
  594. .model(params.getModel())
  595. .knowledgeIds(params.getKnowledge_ids().toString())
  596. .topP(params.getTop_p())
  597. .temperature(params.getTemperature())
  598. .maxToken(params.getMax_token())
  599. .prompt(params.getPrompt())
  600. .knowledgeInfo(params.getKnowledge_info())
  601. .sliceCount(params.getSlice_count())
  602. .build();
  603. int i = takaiApplicationMapper.updateApplication(info);
  604. if (1 > 0) {
  605. TakaiAppInfo appInfo = new TakaiAppInfo();
  606. appInfo.setAppId(appId);
  607. appInfo.setAppInfo(String.valueOf(JSONObject.from(info).toJSONString()));
  608. takaiAppInfoMapper.updateAppInfoByAppId(appInfo);
  609. logger.info("update application success, id:{}, name:{}", appId, params.getName());
  610. //预设问题写入数据库
  611. takaiQuestionMapper.delQuestionByAppId(appId);
  612. List<String> list = params.getQuestionList();
  613. if (!list.isEmpty() && list.size() > 0) {
  614. for (String str : list) {
  615. if (org.apache.commons.lang3.StringUtils.isNotBlank(str)) {
  616. String uuid = IdUtils.simpleUUID();
  617. TakaiQuestion question = TakaiQuestion.builder().id(uuid).question(str).appId(String.valueOf(appId)).build();
  618. takaiQuestionMapper.insertQuestion(question);
  619. }
  620. }
  621. }
  622. }
  623. return i;
  624. }
  625. @Override
  626. public List<TakaiApplication> getApplicationList() {
  627. return takaiApplicationMapper.selectApplicationList(null);
  628. }
  629. @Override
  630. public JSONObject selectApplication(String appId) {
  631. JSONObject object = new JSONObject();
  632. TakaiApplication application = TakaiApplication.builder().appId(appId).build();
  633. TakaiApplication takaiApplication = takaiApplicationMapper.selectTargetApplication(application);
  634. List<TakaiQuestionDTO> list = takaiQuestionMapper.getQuestionList(appId);
  635. object.put("detail", takaiApplication);
  636. object.put("questionlist", list);
  637. return object;
  638. }
  639. @Override
  640. public int delApplication(String appId) {
  641. int i = takaiApplicationMapper.delApplication(appId);
  642. if (i > 0) {
  643. takaiAppInfoMapper.delAppInfoByAppId(appId);
  644. takaiQuestionMapper.delQuestionByAppId(appId);
  645. }
  646. return i;
  647. }
  648. @Override
  649. public List<TakaiQuestionDTO> selectQuestionByAppId(String appId) {
  650. List<TakaiQuestionDTO> List = takaiQuestionMapper.getQuestionList(appId);
  651. return List;
  652. }
  653. @Override
  654. public List<TakaiKnowledge> queryKnowledgeList() {
  655. return takaiKnowledgeMapper.selectKnowledgeList(null);
  656. }
  657. @Override
  658. public List<Object> selectDialogListByAppId(String appId, String userId) {
  659. List<TakaiDialogRespDTO> list = takaiDialogMapper.selectDialog(appId, userId);
  660. List<Object> result = setDialogList(list);
  661. return result;
  662. }
  663. @Override
  664. public TakaiDocumentSettings documentSetting(String documentId) {
  665. return takaiDocumentSettingsMapper.selectById(documentId);
  666. }
  667. @Override
  668. public int updateDocumentSetting(TakaiDocumentSettings documentSettings, String documentId) {
  669. TakaiDocumentSettings settings = new TakaiDocumentSettings();
  670. TakaiDocumentSettings settingsVo = takaiDocumentSettingsMapper.selectById(documentId);
  671. settings.setKnowledgeId(settingsVo.getKnowledgeId());
  672. settings.setSetSlice(documentSettings.getSetSlice());
  673. settings.setSliceValue(documentSettings.getSliceValue());
  674. settings.setSetAnalyze(documentSettings.getSetAnalyze());
  675. settings.setSetTable(documentSettings.getSetTable());
  676. TakaiDocument document = takaiDocumentMapper.selectTargetDocument(TakaiDocument.builder().documentId(documentId).build());
  677. List<UploadDocumentParams> listParams = new ArrayList<>();
  678. if (document != null) {
  679. UploadDocumentParams params = new UploadDocumentParams();
  680. params.setDocument_id(documentId);
  681. params.setName(document.getName());
  682. params.setUrl(document.getUrl());
  683. listParams.add(params);
  684. }
  685. JSONObject jsonObject = analysisFile(listParams, settings, "update");
  686. if (jsonObject != null && jsonObject.containsKey("code") && jsonObject.getInteger("code") == 200) {
  687. logger.info("update document setting success, id:{}", documentId);
  688. documentSettings.setDocumentId(documentId);
  689. return takaiDocumentSettingsMapper.updateDocumentSettings(documentSettings);
  690. }
  691. return 0;
  692. }
  693. @Override
  694. public JSONObject getSliceList(TakaiSliceParams params) {
  695. String url = deepseekConfig.getBaseurl() + deepseekConfig.getSlicePage();
  696. JSONObject jsonObject = new JSONObject();
  697. jsonObject.put("document_id", params.getDocument_id());
  698. jsonObject.put("knowledge_id", params.getKnowledge_id());
  699. jsonObject.put("text", params.getText());
  700. jsonObject.put("pageNum", params.getPageNum());
  701. jsonObject.put("pageSize", params.getPageSize());
  702. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toJSONString());
  703. Request request = buildPostRequest(url, requestBody);
  704. OkHttpClient client = buildOkHttpClient();
  705. Response response = null;
  706. try {
  707. response = client.newCall(request).execute();
  708. if (response.isSuccessful()) {
  709. String body = response.body().string();
  710. JSONObject obj = JSON.parseObject(body);
  711. Integer code = obj.getInteger("code");
  712. if (code == 200) {
  713. return obj;
  714. }
  715. } else {
  716. logger.info("获取切片列表调用python接口失败,返回状态码:{}", response.code());
  717. }
  718. } catch (IOException e) {
  719. logger.error("获取切片列表调用python接口失败", e.getMessage());
  720. }
  721. return null;
  722. }
  723. @Override
  724. public int deleteSlice(String sliceId, String knowledgeId, String documentId) {
  725. String url = deepseekConfig.getBaseurl() + deepseekConfig.getDeleteSlice() + "/" + sliceId + "/" + knowledgeId + "/" + documentId;
  726. Request request = buildDeleteRequest(url);
  727. OkHttpClient client = buildOkHttpClient();
  728. Response response = null;
  729. try {
  730. response = client.newCall(request).execute();
  731. if (response.isSuccessful()) {
  732. String body = response.body().string();
  733. JSONObject obj = JSON.parseObject(body);
  734. Integer code = obj.getInteger("code");
  735. if (code == 200) {
  736. return 1;
  737. }
  738. }
  739. } catch (IOException e) {
  740. logger.error("删除切片调用python接口失败", e.getMessage());
  741. }
  742. return 0;
  743. }
  744. @Override
  745. public JSONObject getSliceDetail(String sliceId, String knowledgeId) {
  746. String url = deepseekConfig.getBaseurl() + deepseekConfig.getSliceDetail() + "/" + knowledgeId + "/" + sliceId;
  747. Request request = buildGetRequest(url);
  748. OkHttpClient client = buildOkHttpClient();
  749. try {
  750. Response response = client.newCall(request).execute();
  751. if (response.isSuccessful()) {
  752. String body = response.body().string();
  753. log.info("查询切片详情返回:" + body);
  754. return JSON.parseObject(body);
  755. } else {
  756. logger.info("获取切片详情调用python接口失败,返回状态码:{}", response.code());
  757. }
  758. } catch (IOException e) {
  759. log.error("查询切片详情调用python接口失败", e.getMessage());
  760. }
  761. return null;
  762. }
  763. @Override
  764. public int updateSliceInfo(TakaiSliceUpdateParams params) {
  765. String url = deepseekConfig.getBaseurl() + deepseekConfig.getUpdateSlice();
  766. JSONObject object = new JSONObject();
  767. object.put("knowledge_id", params.getKnowledgeId());
  768. object.put("slice_id", params.getSliceId());
  769. object.put("slice_text", params.getSliceText());
  770. object.put("document_id", params.getDocumentId());
  771. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), object.toJSONString());
  772. Request request = buildPutRequest(url, requestBody);
  773. OkHttpClient client = buildOkHttpClient();
  774. try {
  775. Response response = client.newCall(request).execute();
  776. if (response.isSuccessful()) {
  777. String body = response.body().string();
  778. JSONObject obj = JSON.parseObject(body);
  779. Integer code = obj.getInteger("code");
  780. if (code == 200) {
  781. return 1;
  782. }
  783. }
  784. } catch (Exception e) {
  785. logger.error("更新切片信息调用python接口失败", e.getMessage());
  786. }
  787. return 0;
  788. }
  789. @Override
  790. public TakaiMediaReplacement getTakaiMediaReplacement() {
  791. TakaiMediaReplacement mrParams = TakaiMediaReplacement.builder()
  792. .documentId("a2912832435041734656")
  793. .originText("【示意图序号_a2912832435041734656_1】")
  794. .mediaType("image").build();
  795. TakaiMediaReplacement mrVo = takaiMediaReplacementMapper.selectTargetMedia(mrParams);
  796. return mrVo;
  797. }
  798. private JSONObject analysisFile(List<UploadDocumentParams> result, TakaiDocumentSettings settings, String flag) {
  799. String url = deepseekConfig.getBaseurl() + deepseekConfig.getUploadKnowledge();
  800. JSONObject json = new JSONObject();
  801. json.put("knowledge_id", settings.getKnowledgeId());
  802. json.put("docs", result);
  803. if ("upload".equals(flag)) {
  804. json.put("set_slice", "0");
  805. json.put("slice_value", null);
  806. json.put("set_analyze", "1");
  807. json.put("set_table", "0");
  808. json.put("flag", "upload");
  809. } else {
  810. json.put("set_slice", settings.getSetSlice());
  811. json.put("slice_value", settings.getSliceValue());
  812. json.put("set_analyze", settings.getSetAnalyze());
  813. json.put("set_table", settings.getSetTable());
  814. json.put("flag", "update");
  815. }
  816. RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), json.toJSONString());
  817. Request request = buildPostRequest(url, requestBody);
  818. OkHttpClient client = buildOkHttpClient();
  819. Response response = null;
  820. try {
  821. response = client.newCall(request).execute();
  822. if (response.isSuccessful()) {
  823. String body = response.body().string();
  824. JSONObject obj = JSON.parseObject(body);
  825. Integer code = obj.getInteger("code");
  826. if (code == 200) {
  827. logger.info("上传文档调用python接口成功,返回内容:{}", body);
  828. return obj;
  829. }
  830. return obj;
  831. } else {
  832. logger.error("上传文档调用python接口失败返回code:{}", response.code());
  833. return null;
  834. }
  835. } catch (IOException e) {
  836. logger.error("上传文档调用python接口失败", e.getMessage());
  837. return null;
  838. }
  839. }
  840. private List<Object> setDialogList(List<TakaiDialogRespDTO> list) {
  841. //根据时间分组降序排序
  842. NavigableMap<LocalDateTime, List<TakaiDialogRespDTO>> groupList = list.stream().collect(Collectors.groupingBy(TakaiDialogRespDTO::getCreate_time, TreeMap::new, Collectors.toList())).descendingMap();
  843. List<Object> obj = new ArrayList();
  844. if (!groupList.isEmpty()) {
  845. for (Map.Entry<LocalDateTime, List<TakaiDialogRespDTO>> entry : groupList.entrySet()) {
  846. List<TakaiDialogRespDTO> aList = entry.getValue();
  847. List<TakaiDialogRespDTO> detailList = takaiDialogMapper.selectDialogExport(aList.get(0).getId());
  848. Map<String, Object> map = new HashMap();
  849. map.put("dialog_name", aList.get(0).getDialog_name());
  850. map.put("length", detailList.size());
  851. map.put("create_time", aList.get(0).getCreate_time());
  852. map.put("did", aList.get(0).getDid());
  853. map.put("id", aList.get(0).getId());
  854. obj.add(map);
  855. }
  856. }
  857. return obj;
  858. }
  859. private List<Map<String, Object>> setValue(List<TakaiDialogRespDTO> list) {
  860. List<Map<String, Object>> l = new ArrayList();
  861. for (TakaiDialogRespDTO vo : list) {
  862. Map<String, Object> map = new HashMap();
  863. map.put("key", vo.getId());
  864. map.put("label", vo.getDialog_name());
  865. l.add(map);
  866. }
  867. return l;
  868. }
  869. private OkHttpClient buildOkHttpClient() {
  870. return new OkHttpClient.Builder()
  871. .connectTimeout(10, TimeUnit.SECONDS)
  872. .writeTimeout(50, TimeUnit.SECONDS)
  873. .readTimeout(10, TimeUnit.MINUTES)
  874. .build();
  875. }
  876. private Request buildGetRequest(String url) {
  877. return new Request.Builder()
  878. .addHeader("User-Agent", "insomnia/10.3.1")
  879. .url(url).get().build();
  880. }
  881. private Request buildPostRequest(String url, RequestBody requestBody) {
  882. return new Request.Builder()
  883. .addHeader("User-Agent", "insomnia/10.3.1")
  884. .addHeader("Content-Type", "application/json")
  885. .url(url).post(requestBody).build();
  886. }
  887. private Request buildPutRequest(String url, RequestBody requestBody) {
  888. return new Request.Builder()
  889. .addHeader("User-Agent", "insomnia/10.3.1")
  890. .url(url).put(requestBody).build();
  891. }
  892. private Request buildDeleteRequest(String url) {
  893. return new Request.Builder()
  894. .addHeader("Content-Type", "multipart/form-data")
  895. .addHeader("User-Agent", "insomnia/10.3.1")
  896. .url(url).delete().build();
  897. }
  898. private Request buildUploadPostRequest(String url, RequestBody requestBody) {
  899. return new Request.Builder()
  900. .addHeader("User-Agent", "insomnia/10.3.1")
  901. .addHeader("Content-Type", "application/json")
  902. .url(url).post(requestBody).build();
  903. }
  904. private boolean isJsonObject(String data) {
  905. try {
  906. JSON.parseObject(data);
  907. return true;
  908. } catch (Exception e) {
  909. return false;
  910. }
  911. }
  912. }