Skip to content

Commit ddf961d

Browse files
committed
feat:add web and update knowledgeChat
1 parent 0f435e5 commit ddf961d

File tree

255 files changed

+42593
-51
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

255 files changed

+42593
-51
lines changed

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ mysql,redis,emqx和influxdb环境。
8888
欢迎加入群聊一起交流讨论有关Aiot相关的话题,免费获取智控台的前端源码,链接过期了可以issue或email提醒一下作者。
8989

9090
<div style="width: 250px;margin: 0 auto;">
91-
<img src="./images/ede859c2bbe032886b842748dcfdc503.jpg" width="250px"/>
91+
<img src="./images/728a85f486074938ba54d89a6eb6171f.jpg" width="250px"/>
9292
</div>
9393

9494

163 KB
Loading
-162 KB
Binary file not shown.

pom.xml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
<dependency>
160160
<groupId>commons-io</groupId>
161161
<artifactId>commons-io</artifactId>
162-
<version>2.7</version>
162+
<version>2.15.1</version>
163163
</dependency>
164164
<dependency>
165165
<groupId>org.apache.commons</groupId>
@@ -293,6 +293,31 @@
293293
<artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
294294
<version>1.0.0-beta3</version>
295295
</dependency>
296+
<dependency>
297+
<groupId>org.apache.poi</groupId>
298+
<artifactId>poi</artifactId>
299+
<version>5.2.3</version>
300+
</dependency>
301+
<dependency>
302+
<groupId>org.apache.poi</groupId>
303+
<artifactId>poi-ooxml</artifactId>
304+
<version>5.2.3</version>
305+
</dependency>
306+
<dependency>
307+
<groupId>org.apache.poi</groupId>
308+
<artifactId>poi-scratchpad</artifactId>
309+
<version>5.2.3</version>
310+
</dependency>
311+
<dependency>
312+
<groupId>dev.langchain4j</groupId>
313+
<artifactId>langchain4j-document-parser-apache-poi</artifactId>
314+
<version>1.8.0-beta15</version>
315+
</dependency>
316+
<dependency>
317+
<groupId>dev.langchain4j</groupId>
318+
<artifactId>langchain4j-document-parser-markdown</artifactId>
319+
<version>1.8.0-beta15</version>
320+
</dependency>
296321
<!-- 音频处理 -->
297322
<dependency>
298323
<groupId>ws.schild</groupId>

readme.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,18 @@ mysql,redis,emqx和influxdb环境,安装详情请看官方文档。
113113

114114
## 交流群
115115

116-
欢迎加入群聊一起交流讨论有关Aiot相关的话题,免费获取智控台的前端源码,链接过期了可以issue或email提醒一下作者。
116+
欢迎加入群聊一起交流讨论有关Aiot相关的话题,有机会获取项目的免费部署咨询,链接过期了可以issue或email提醒一下作者。
117117

118118
<div style="width: 250px;margin: 0 auto;">
119-
<img src="./docs/images/ede859c2bbe032886b842748dcfdc503.jpg" width="250px"/>
119+
<img src="./docs/images/728a85f486074938ba54d89a6eb6171f.jpg" width="250px"/>
120120
</div>
121121

122122
## 致谢
123123
* 感谢项目[xiaozhi-esp32](https://github.com/78/xiaozhi-esp32)提供强大的硬件语音交互。
124124
* 感谢项目[Concentus: Opus for Everyone](https://github.com/lostromb/concentus)提供opus解码和编码。
125125
* 感谢项目[TalkX](https://github.com/big-mouth-cn/talkx)提供了opus解码和编码的参考。
126126
* 感谢项目[py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi)方便项目进行小智开发调试。
127+
* 感谢项目[vue3-antd-manage](https://github.com/BaiFangZi/vue3-antd-manage)本项目智控台基于该项目二次开发。
127128
* [电波bilibili君](https://space.bilibili.com/119751)赞助项目开发。
128129

129130
## 授权协议

src/main/java/top/rslly/iot/controllers/Tool.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,21 @@ public JsonResult<?> getKnowledgeChat(@RequestHeader("Authorization") String hea
180180
return knowledgeChatService.getKnowledgeChat(header);
181181
}
182182

183+
@Operation(summary = "知识库", description = "搜索产品的知识库")
184+
@RequestMapping(value = "/knowledgeChatRecall", method = RequestMethod.POST)
185+
public JsonResult<?> searchKnowledgeChat(
186+
@Valid @RequestBody KnowledgeChatRecall knowledgeChatRecall,
187+
@RequestHeader("Authorization") String header) {
188+
try {
189+
if (!safetyService.controlAuthorizeProduct(header, knowledgeChatRecall.getProductId()))
190+
return ResultTool.fail(ResultCode.NO_PERMISSION);
191+
} catch (NullPointerException e) {
192+
return ResultTool.fail(ResultCode.PARAM_NOT_VALID);
193+
}
194+
return knowledgeChatService.searchByProductId(knowledgeChatRecall.getProductId(),
195+
knowledgeChatRecall.getQuery());
196+
}
197+
183198
@Operation(summary = "知识库", description = "提交产品的知识库")
184199
@RequestMapping(value = "/knowledgeChat", method = RequestMethod.POST)
185200
public JsonResult<?> postKnowledgeChat(@RequestParam("productId") int productId,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright © 2023-2030 The ruanrongman Authors
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
package top.rslly.iot.param.request;
21+
22+
import lombok.Data;
23+
24+
import javax.validation.constraints.NotBlank;
25+
import javax.validation.constraints.Size;
26+
27+
@Data
28+
public class KnowledgeChatRecall {
29+
int productId;
30+
@NotBlank(message = "query 不能为空")
31+
@Size(min = 1, max = 2048, message = "description 长度必须在 1 到 2048 之间")
32+
String query;
33+
}

src/main/java/top/rslly/iot/param/request/ProductRole.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class ProductRole {
3737
@Size(min = 1, max = 255, message = "role 长度必须在 1 到 255 之间")
3838
private String role;
3939
@NotBlank(message = "roleIntroduction 不能为空")
40-
@Size(min = 1, max = 255, message = "roleIntroduction 长度必须在 1 到 255 之间")
40+
@Size(min = 1, max = 2048, message = "roleIntroduction 长度必须在 1 到 255 之间")
4141
private String roleIntroduction;
4242
@NotBlank(message = "voice 不能为空")
4343
@Size(min = 1, max = 255, message = "voice 长度必须在 1 到 255 之间")

src/main/java/top/rslly/iot/services/agent/KnowledgeChatService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public interface KnowledgeChatService {
3131

3232
String searchByProductId(String productId, String query);
3333

34+
JsonResult<?> searchByProductId(int productId, String query);
35+
3436
JsonResult<?> getKnowledgeChat(String token);
3537

3638
JsonResult<?> postKnowledgeChat(int productId, String fileName, MultipartFile multipartFile);

src/main/java/top/rslly/iot/services/agent/KnowledgeChatServiceImpl.java

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@
4545
import java.io.IOException;
4646
import java.nio.file.Files;
4747
import java.util.ArrayList;
48+
import java.util.HashMap;
4849
import java.util.List;
50+
import java.util.Map;
4951
import java.util.stream.Collectors;
5052

5153
@Service
@@ -92,6 +94,35 @@ public String searchByProductId(String productId, String query) {
9294
}
9395
}
9496

97+
@Override
98+
public JsonResult<?> searchByProductId(int productId, String query) {
99+
// 1. 检查 productId 是否存在
100+
var res = knowledgeChatRepository.findAllByProductId(productId);
101+
if (res.isEmpty()) {
102+
// 2. 如果不存在,返回空列表
103+
return ResultTool.fail(ResultCode.PARAM_NOT_VALID);
104+
}
105+
106+
try {
107+
EmbeddingSearchResult<TextSegment> searchResult = RagUtility.searchByProductId(
108+
knowledgeChatEmbeddingStore, embeddingModel, query, String.valueOf(productId));
109+
var result = searchResult.matches().stream()
110+
.map(match -> {
111+
Map<String, Object> item = new HashMap<>();
112+
item.put("text", match.embedded().text());
113+
item.put("score", match.score());
114+
return item;
115+
})
116+
.collect(Collectors.toList());
117+
return ResultTool.success(result);
118+
119+
} catch (Exception e) {
120+
log.error("查询知识库失败: {}", e.getMessage(), e); // 建议将异常堆栈也打印出来
121+
// 4. 异常时也返回空列表
122+
return ResultTool.success(new ArrayList<>());
123+
}
124+
}
125+
95126
@Override
96127
public JsonResult<?> getKnowledgeChat(String token) {
97128
String token_deal = token.replace(JwtTokenUtil.TOKEN_PREFIX, "");
@@ -152,11 +183,15 @@ public JsonResult<?> postKnowledgeChat(int productId, String fileName,
152183
String realFileName = multipartFile.getOriginalFilename();
153184
if (realFileName == null)
154185
return ResultTool.fail(ResultCode.PARAM_NOT_COMPLETE);
155-
String suffixName = realFileName.substring(realFileName.lastIndexOf(".")); // 后缀名
156-
if (!suffixName.equals(".pdf"))
186+
String suffixName = realFileName.substring(realFileName.lastIndexOf(".")).toLowerCase(); // 后缀名
187+
// 允许的文件类型
188+
List<String> allowedSuffixes = List.of(".pdf", ".txt", ".md", ".markdown", ".doc", ".docx",
189+
".ppt", ".pptx", ".xls", ".xlsx");
190+
if (!allowedSuffixes.contains(suffixName)) {
157191
return ResultTool.fail(ResultCode.PARAM_NOT_VALID);
192+
}
158193
try {
159-
File tempFile = Files.createTempFile("upload-", ".pdf").toFile();
194+
File tempFile = Files.createTempFile("upload-", suffixName).toFile();
160195
multipartFile.transferTo(tempFile);
161196
KnowledgeChatEntity knowledgeChatEntity = new KnowledgeChatEntity();
162197
knowledgeChatEntity.setFilename(fileName);
@@ -165,7 +200,7 @@ public JsonResult<?> postKnowledgeChat(int productId, String fileName,
165200
var result = knowledgeChatRepository.save(knowledgeChatEntity);
166201
taskExecutor.execute(() -> {
167202
try {
168-
RagUtility.ingestPdfToChroma(tempFile.getAbsolutePath(), String.valueOf(productId),
203+
RagUtility.ingestFileToChroma(tempFile.getAbsolutePath(), String.valueOf(productId),
169204
fileName, embeddingModel, knowledgeChatEmbeddingStore);
170205
knowledgeChatEntity.setStatus("success");
171206
knowledgeChatEntity.setId(result.getId());
@@ -175,10 +210,19 @@ public JsonResult<?> postKnowledgeChat(int productId, String fileName,
175210
knowledgeChatEntity.setStatus("error");
176211
knowledgeChatEntity.setId(result.getId());
177212
knowledgeChatRepository.save(knowledgeChatEntity);
213+
} finally {
214+
// 删除临时文件
215+
if (tempFile.exists()) {
216+
boolean deleted = tempFile.delete();
217+
if (!deleted) {
218+
log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
219+
}
220+
}
178221
}
179222
});
180223
return ResultTool.success();
181224
} catch (IOException e) {
225+
log.error("文件上传失败: {}", e.getMessage(), e);
182226
return ResultTool.fail(ResultCode.COMMON_FAIL);
183227
}
184228
}

0 commit comments

Comments
 (0)