TakaiAiServiceImpl.java 43 KB

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