TakaiAiServiceImpl.java 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  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.setDocumentId("a" + documentId);
  442. settings.setKnowledgeId(knowledgeId);
  443. boolean flag = analysisFile(params, settings, "upload");
  444. if (flag) {
  445. for (TakaiSysOss oss : result) {
  446. // oss保存到数据库
  447. takaiSysOssMapper.insertSysOss(oss);
  448. }
  449. for (UploadDocumentParams vo : params) {
  450. // 保存知识信息
  451. TakaiDocument document = TakaiDocument.builder()
  452. .documentId(vo.getDocument_id())
  453. .knowledgeId(knowledgeId)
  454. .customSeparator(String.format("[\"%s\"", "\\n") + "]")
  455. .sentenceSize("300")
  456. .name(vo.getName())
  457. .url(vo.getUrl()).build();
  458. int documentIdInsert = takaiDocumentMapper.insertDocument(document);
  459. if (documentIdInsert > 0) {
  460. // 保存知识设置信息
  461. SnowflakeDigitGenerator snowflakeDigitGenerator = new SnowflakeDigitGenerator(1, 1);
  462. long id = snowflakeDigitGenerator.nextId();
  463. TakaiDocumentSettings dSettings = new TakaiDocumentSettings();
  464. dSettings.setId(String.valueOf(id));
  465. dSettings.setKnowledgeId(knowledgeId);
  466. dSettings.setDocumentId(vo.getDocument_id());
  467. dSettings.setSetSlice("0"); // 默认 按标题段落切片
  468. dSettings.setSetAnalyze("1"); // 默认 图片转换成标识符
  469. dSettings.setSetTable("0"); // 默认 ttable转图片
  470. takaiDocumentSettingsMapper.insertDocumentSettings(dSettings);
  471. }
  472. }
  473. setRedisCache(knowledgeId);
  474. return 1;
  475. }
  476. }
  477. return 0;
  478. }
  479. @Override
  480. public int updateDocument(TakaiDocumentParams documentParams, String documentId) {
  481. int i = takaiDocumentMapper.updateDocument(TakaiDocument.builder()
  482. .documentId(documentId)
  483. .name(documentParams.getName())
  484. .build());
  485. return i;
  486. }
  487. @Override
  488. public List<TakaiDocument> documentList(TakaiDocumentParams documentParams) {
  489. return takaiDocumentMapper.selectDocumentList(TakaiDocument.builder().knowledgeId(documentParams.getKnowledge_id()).build());
  490. }
  491. @Override
  492. public TakaiDocument documentDetail(String documentId) {
  493. return takaiDocumentMapper.selectTargetDocument(TakaiDocument.builder().documentId(documentId).build());
  494. }
  495. @Override
  496. public int delDocument(String documentId) {
  497. TakaiDocument vo = takaiDocumentMapper.selectTargetDocument(TakaiDocument.builder().documentId(documentId).build());
  498. if(vo != null){
  499. String url = deepseekConfig.getBaseurl() + deepseekConfig.getDeleteDoc() + "/" + documentId + "/" + vo.getKnowledgeId();
  500. Request request = buildDeleteRequest(url);
  501. OkHttpClient client = buildOkHttpClient();
  502. try {
  503. Response response = client.newCall(request).execute();
  504. if (response.isSuccessful()) {
  505. String body = response.body().string();
  506. logger.info("删除知识文件调用python接口返回结果:{}", body);
  507. JSONObject obj = JSON.parseObject(body);
  508. Integer code = obj.getInteger("code");
  509. if (code == 200) {
  510. return takaiDocumentMapper.delDocument(documentId);
  511. }
  512. }
  513. } catch (IOException e) {
  514. logger.error("删除知识文件调用python接口失败", e.getMessage());
  515. }
  516. }
  517. return 0;
  518. }
  519. @Override
  520. public void uploadUrl(TakaiDocumentObject object) {
  521. }
  522. @Override
  523. public int createApplication(TakaiApplicationParams params) {
  524. SnowflakeDigitGenerator snowflakeDigitGenerator = new SnowflakeDigitGenerator(1, 1);
  525. long appId = snowflakeDigitGenerator.nextId();
  526. TakaiApplication info = TakaiApplication.builder().appId(String.valueOf(appId))
  527. .name(params.getName())
  528. .desc(params.getDesc())
  529. .model(params.getModel())
  530. .knowledgeIds(params.getKnowledge_ids().toString())
  531. .topP(params.getTop_p())
  532. .temperature(params.getTemperature())
  533. .maxToken(params.getMax_token())
  534. .prompt(params.getPrompt())
  535. .knowledgeInfo(params.getKnowledge_info())
  536. .sliceCount(params.getSlice_count())
  537. .build();
  538. int i = takaiApplicationMapper.insertApplication(info);
  539. if (i > 0) {
  540. logger.info("create application success, id:{}, name:{}", appId, params.getName());
  541. TakaiAppInfo appInfo = new TakaiAppInfo();
  542. appInfo.setAppId(String.valueOf(appId));
  543. appInfo.setAppInfo(String.valueOf(JSONObject.from(info).toJSONString()));
  544. takaiAppInfoMapper.insertAppInfo(appInfo);
  545. List<String> list = params.getQuestionList();
  546. if (!list.isEmpty() && list.size() > 0) {
  547. for (String str : list) {
  548. if (org.apache.commons.lang3.StringUtils.isNotBlank(str)) {
  549. String uuid = IdUtils.simpleUUID();
  550. TakaiQuestion question = TakaiQuestion.builder().id(uuid).question(str).appId(String.valueOf(appId)).build();
  551. takaiQuestionMapper.insertQuestion(question);
  552. }
  553. }
  554. }
  555. }
  556. return i;
  557. }
  558. @Override
  559. public int updateApplication(TakaiApplicationParams params, String appId) {
  560. TakaiApplication info = TakaiApplication.builder().appId(appId)
  561. .name(params.getName())
  562. .desc(params.getDesc())
  563. .model(params.getModel())
  564. .knowledgeIds(params.getKnowledge_ids().toString())
  565. .topP(params.getTop_p())
  566. .temperature(params.getTemperature())
  567. .maxToken(params.getMax_token())
  568. .prompt(params.getPrompt())
  569. .knowledgeInfo(params.getKnowledge_info())
  570. .sliceCount(params.getSlice_count())
  571. .build();
  572. int i = takaiApplicationMapper.updateApplication(info);
  573. if (1 > 0) {
  574. TakaiAppInfo appInfo = new TakaiAppInfo();
  575. appInfo.setAppId(appId);
  576. appInfo.setAppInfo(String.valueOf(JSONObject.from(info).toJSONString()));
  577. takaiAppInfoMapper.updateAppInfoByAppId(appInfo);
  578. logger.info("update application success, id:{}, name:{}", appId, params.getName());
  579. //预设问题写入数据库
  580. takaiQuestionMapper.delQuestionByAppId(appId);
  581. List<String> list = params.getQuestionList();
  582. if (!list.isEmpty() && list.size() > 0) {
  583. for (String str : list) {
  584. if (org.apache.commons.lang3.StringUtils.isNotBlank(str)) {
  585. String uuid = IdUtils.simpleUUID();
  586. TakaiQuestion question = TakaiQuestion.builder().id(uuid).question(str).appId(String.valueOf(appId)).build();
  587. takaiQuestionMapper.insertQuestion(question);
  588. }
  589. }
  590. }
  591. }
  592. return i;
  593. }
  594. @Override
  595. public List<TakaiApplication> getApplicationList() {
  596. return takaiApplicationMapper.selectApplicationList(null);
  597. }
  598. @Override
  599. public JSONObject selectApplication(String appId) {
  600. JSONObject object = new JSONObject();
  601. TakaiApplication application = TakaiApplication.builder().appId(appId).build();
  602. TakaiApplication takaiApplication = takaiApplicationMapper.selectTargetApplication(application);
  603. List<TakaiQuestionDTO> list = takaiQuestionMapper.getQuestionList(appId);
  604. object.put("detail", takaiApplication);
  605. object.put("questionlist", list);
  606. return object;
  607. }
  608. @Override
  609. public int delApplication(String appId) {
  610. int i = takaiApplicationMapper.delApplication(appId);
  611. if (i > 0) {
  612. takaiAppInfoMapper.delAppInfoByAppId(appId);
  613. takaiQuestionMapper.delQuestionByAppId(appId);
  614. }
  615. return i;
  616. }
  617. @Override
  618. public List<TakaiQuestionDTO> selectQuestionByAppId(String appId) {
  619. List<TakaiQuestionDTO> List = takaiQuestionMapper.getQuestionList(appId);
  620. return List;
  621. }
  622. @Override
  623. public List<TakaiKnowledge> queryKnowledgeList() {
  624. return takaiKnowledgeMapper.selectKnowledgeList(null);
  625. }
  626. @Override
  627. public List<Object> selectDialogListByAppId(String appId, String userId) {
  628. List<TakaiDialogRespDTO> list = takaiDialogMapper.selectDialog(appId, userId);
  629. List<Object> result = setDialogList(list);
  630. return result;
  631. }
  632. @Override
  633. public TakaiDocumentSettings documentSetting(String documentId) {
  634. return takaiDocumentSettingsMapper.selectById(documentId);
  635. }
  636. @Override
  637. public int updateDocumentSetting(TakaiDocumentSettings documentSettings, String documentId) {
  638. TakaiDocumentSettings settings = new TakaiDocumentSettings();
  639. TakaiDocumentSettings settingsVo = takaiDocumentSettingsMapper.selectById(documentId);
  640. settings.setKnowledgeId(settingsVo.getKnowledgeId());
  641. settings.setSetSlice(documentSettings.getSetSlice());
  642. settings.setSliceValue(documentSettings.getSliceValue());
  643. settings.setSetAnalyze(documentSettings.getSetAnalyze());
  644. settings.setSetTable(documentSettings.getSetTable());
  645. TakaiDocument document = takaiDocumentMapper.selectTargetDocument(TakaiDocument.builder().documentId(documentId).build());
  646. List<UploadDocumentParams> listParams = new ArrayList<>();
  647. if (document != null) {
  648. UploadDocumentParams params = new UploadDocumentParams();
  649. params.setDocument_id(documentId);
  650. params.setName(document.getName());
  651. params.setUrl(document.getUrl());
  652. listParams.add(params);
  653. }
  654. boolean status = analysisFile(listParams, settings, "update");
  655. if (status) {
  656. logger.info("update document setting success, id:{}", documentId);
  657. documentSettings.setDocumentId(documentId);
  658. int i = takaiDocumentSettingsMapper.updateDocumentSettings(documentSettings);
  659. return i;
  660. }
  661. return 0;
  662. }
  663. @Override
  664. public JSONObject getSliceList(TakaiSliceParams params) {
  665. String url = deepseekConfig.getBaseurl() + deepseekConfig.getSlicePage();
  666. JSONObject jsonObject = new JSONObject();
  667. jsonObject.put("document_id", params.getDocument_id());
  668. jsonObject.put("knowledge_id", params.getKnowledge_id());
  669. jsonObject.put("text", params.getText());
  670. jsonObject.put("pageNum", params.getPageNum());
  671. jsonObject.put("pageSize", params.getPageSize());
  672. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toJSONString());
  673. Request request = buildPostRequest(url, requestBody);
  674. OkHttpClient client = buildOkHttpClient();
  675. Response response = null;
  676. try {
  677. response = client.newCall(request).execute();
  678. if (response.isSuccessful()) {
  679. String body = response.body().string();
  680. JSONObject obj = JSON.parseObject(body);
  681. Integer code = obj.getInteger("code");
  682. if (code == 200) {
  683. return obj;
  684. }
  685. } else {
  686. logger.info("获取切片列表调用python接口失败,返回状态码:{}", response.code());
  687. }
  688. } catch (IOException e) {
  689. logger.error("获取切片列表调用python接口失败", e.getMessage());
  690. }
  691. return null;
  692. }
  693. @Override
  694. public int deleteSlice(String sliceId, String knowledgeId) {
  695. // TakaiKnowledge knowledge = takaiKnowledgeMapper.selectTargetKnowledge(TakaiKnowledge.builder().knowledgeId(knowledgeId).build());
  696. String url = deepseekConfig.getBaseurl() + deepseekConfig.getDeleteSlice() + "/" + sliceId + "/" + knowledgeId;
  697. Request request = buildDeleteRequest(url);
  698. OkHttpClient client = buildOkHttpClient();
  699. Response response = null;
  700. try {
  701. response = client.newCall(request).execute();
  702. if (response.isSuccessful()) {
  703. String body = response.body().string();
  704. JSONObject obj = JSON.parseObject(body);
  705. Integer code = obj.getInteger("code");
  706. if (code == 200) {
  707. return 1;
  708. }
  709. }
  710. } catch (IOException e) {
  711. logger.error("删除切片调用python接口失败", e.getMessage());
  712. }
  713. return 0;
  714. }
  715. @Override
  716. public JSONObject getSliceDetail(String sliceId, String knowledgeId) {
  717. String url = deepseekConfig.getBaseurl() + deepseekConfig.getSliceDetail() + "/" + knowledgeId + "/" + sliceId;
  718. Request request = buildGetRequest(url);
  719. OkHttpClient client = buildOkHttpClient();
  720. try {
  721. Response response = client.newCall(request).execute();
  722. if (response.isSuccessful()) {
  723. String body = response.body().string();
  724. log.info("查询切片详情返回:" + body);
  725. return JSON.parseObject(body);
  726. } else {
  727. logger.info("获取切片详情调用python接口失败,返回状态码:{}", response.code());
  728. }
  729. } catch (IOException e) {
  730. log.error("查询切片详情调用python接口失败", e.getMessage());
  731. }
  732. return null;
  733. }
  734. @Override
  735. public int updateSliceInfo(TakaiSliceUpdateParams params) {
  736. String url = deepseekConfig.getBaseurl() + deepseekConfig.getUpdateSlice();
  737. JSONObject object = new JSONObject();
  738. object.put("knowledge_id", params.getKnowledgeId());
  739. object.put("slice_id", params.getSliceId());
  740. object.put("slice_text", params.getSliceText());
  741. RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), object.toJSONString());
  742. Request request = buildPutRequest(url, requestBody);
  743. OkHttpClient client = buildOkHttpClient();
  744. try {
  745. Response response = client.newCall(request).execute();
  746. if (response.isSuccessful()) {
  747. String body = response.body().string();
  748. JSONObject obj = JSON.parseObject(body);
  749. Integer code = obj.getInteger("code");
  750. if (code == 200) {
  751. return 1;
  752. }
  753. }
  754. } catch (Exception e) {
  755. logger.error("更新切片信息调用python接口失败", e.getMessage());
  756. }
  757. return 0;
  758. }
  759. @Override
  760. public TakaiMediaReplacement getTakaiMediaReplacement() {
  761. TakaiMediaReplacement mrParams = TakaiMediaReplacement.builder()
  762. .documentId("a2912832435041734656")
  763. .originText("【示意图序号_a2912832435041734656_1】")
  764. .mediaType("image").build();
  765. TakaiMediaReplacement mrVo = takaiMediaReplacementMapper.selectTargetMedia(mrParams);
  766. return mrVo;
  767. }
  768. private boolean analysisFile(List<UploadDocumentParams> result, TakaiDocumentSettings settings, String flag) {
  769. // TakaiKnowledge knowledge = takaiKnowledgeMapper.selectTargetKnowledge(TakaiKnowledge.builder().knowledgeId(settings.getKnowledgeId()).build());
  770. String url = deepseekConfig.getBaseurl() + deepseekConfig.getUploadKnowledge();
  771. JSONObject json = new JSONObject();
  772. json.put("knowledge_id", settings.getKnowledgeId());
  773. // json.put("document_id", settings.getDocumentId());
  774. // json.put("embedding_id", knowledge == null ? "" : knowledge.getEmbeddingId());
  775. json.put("docs", result);
  776. // json.put("name", result.getOriginalName());
  777. // json.put("url", result.getUrl());
  778. if ("upload".equals(flag)) {
  779. json.put("set_slice", "0");
  780. json.put("slice_value", null);
  781. json.put("set_analyze", "1");
  782. json.put("set_table", "0");
  783. json.put("flag", "upload");
  784. } else {
  785. json.put("set_slice", settings.getSetSlice());
  786. json.put("slice_value", settings.getSliceValue());
  787. json.put("set_analyze", settings.getSetAnalyze());
  788. json.put("set_table", settings.getSetTable());
  789. json.put("flag", "update");
  790. }
  791. RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), json.toJSONString());
  792. Request request = buildPostRequest(url, requestBody);
  793. OkHttpClient client = buildOkHttpClient();
  794. Response response = null;
  795. try {
  796. response = client.newCall(request).execute();
  797. if (response.isSuccessful()) {
  798. String body = response.body().string();
  799. JSONObject obj = JSON.parseObject(body);
  800. Integer code = obj.getInteger("code");
  801. if (code == 200) {
  802. logger.info("上传文档调用python接口成功,返回内容:{}", body);
  803. return true;
  804. }
  805. return false;
  806. } else {
  807. logger.error("上传文档调用python接口失败返回code:{}", response.code());
  808. return false;
  809. }
  810. } catch (IOException e) {
  811. logger.error("上传文档调用python接口失败", e.getMessage());
  812. return false;
  813. }
  814. }
  815. private List<Object> setDialogList(List<TakaiDialogRespDTO> list) {
  816. //根据时间分组降序排序
  817. NavigableMap<LocalDateTime, List<TakaiDialogRespDTO>> groupList = list.stream().collect(Collectors.groupingBy(TakaiDialogRespDTO::getCreate_time, TreeMap::new, Collectors.toList())).descendingMap();
  818. List<Object> obj = new ArrayList();
  819. if (!groupList.isEmpty()) {
  820. for (Map.Entry<LocalDateTime, List<TakaiDialogRespDTO>> entry : groupList.entrySet()) {
  821. List<TakaiDialogRespDTO> aList = entry.getValue();
  822. List<TakaiDialogRespDTO> detailList = takaiDialogMapper.selectDialogExport(aList.get(0).getId());
  823. Map<String, Object> map = new HashMap();
  824. map.put("dialog_name", aList.get(0).getDialog_name());
  825. map.put("length", detailList.size());
  826. map.put("create_time", aList.get(0).getCreate_time());
  827. map.put("did", aList.get(0).getDid());
  828. map.put("id", aList.get(0).getId());
  829. obj.add(map);
  830. }
  831. }
  832. return obj;
  833. }
  834. private List<Map<String, Object>> setValue(List<TakaiDialogRespDTO> list) {
  835. List<Map<String, Object>> l = new ArrayList();
  836. for (TakaiDialogRespDTO vo : list) {
  837. Map<String, Object> map = new HashMap();
  838. map.put("key", vo.getId());
  839. map.put("label", vo.getDialog_name());
  840. l.add(map);
  841. }
  842. return l;
  843. }
  844. private OkHttpClient buildOkHttpClient() {
  845. return new OkHttpClient.Builder()
  846. .connectTimeout(10, TimeUnit.SECONDS)
  847. .writeTimeout(50, TimeUnit.SECONDS)
  848. .readTimeout(10, TimeUnit.MINUTES)
  849. .build();
  850. }
  851. private Request buildGetRequest(String url) {
  852. return new Request.Builder()
  853. .addHeader("User-Agent", "insomnia/10.3.1")
  854. .url(url).get().build();
  855. }
  856. private Request buildPostRequest(String url, RequestBody requestBody) {
  857. return new Request.Builder()
  858. .addHeader("User-Agent", "insomnia/10.3.1")
  859. .addHeader("Content-Type", "application/json")
  860. .url(url).post(requestBody).build();
  861. }
  862. private Request buildPutRequest(String url, RequestBody requestBody) {
  863. return new Request.Builder()
  864. .addHeader("User-Agent", "insomnia/10.3.1")
  865. .url(url).put(requestBody).build();
  866. }
  867. private Request buildDeleteRequest(String url) {
  868. return new Request.Builder()
  869. .addHeader("Content-Type", "multipart/form-data")
  870. .addHeader("User-Agent", "insomnia/10.3.1")
  871. .url(url).delete().build();
  872. }
  873. private Request buildUploadPostRequest(String url, RequestBody requestBody) {
  874. return new Request.Builder()
  875. .addHeader("User-Agent", "insomnia/10.3.1")
  876. .addHeader("Content-Type", "application/json")
  877. .url(url).post(requestBody).build();
  878. }
  879. private boolean isJsonObject(String data) {
  880. try {
  881. JSON.parseObject(data);
  882. return true;
  883. } catch (Exception e) {
  884. return false;
  885. }
  886. }
  887. }