ModelService GpuType 是 ServerName 表ID
+ * 模型补全流式处理方法
*
- * @param gpuType gpuType
- * @return host
+ * @param url 模型服务的 URL
+ * @param req 模型补全请求对象
*/
- public String getHostByType (Long gpuType) {
- return serverNameService.getServerName(gpuType).getHost();
+ public void modelCompletionsStream (String url, ModelCompletionsReqVO req, SseEmitter emitter, HttpServletResponse response) {
+ req.setStream(true);
+ log.info("开始处理模型补全请求,参数: {}", req);
+ try {
+ log.info("开始处理模型补全请求,参数: {}", JSON.toJSONString(req));
+ sendPostRequest(url, JSON.toJSONString(req), emitter);
+ } catch (Exception e) {
+ emitter.completeWithError(e);
+ }
+ }
+
+ /**
+ * 发送 POST 请求并处理响应
+ *
+ * @param apiUrl 目标 API 的 URL
+ * @param requestBody 请求体内容
+ * @throws IOException 发送请求或处理响应时可能抛出的 IO 异常
+ */
+ private void sendPostRequest (String apiUrl, String requestBody, SseEmitter emitter) throws IOException {
+ // 创建 HttpClient 实例
+ HttpClient httpClient = HttpClients.createDefault();
+ // 创建 HttpPost 请求对象
+ HttpPost httpPost = new HttpPost(apiUrl);
+
+ // 设置请求体和请求头
+ setupRequest(httpPost, requestBody);
+
+ // 执行 POST 请求并获取响应
+ HttpResponse response = httpClient.execute(httpPost);
+
+ // 处理响应实体
+ handleResponseEntity(response, emitter);
+ }
+
+ /**
+ * 设置请求体和请求头
+ *
+ * @param httpPost HttpPost 请求对象
+ * @param requestBody 请求体内容
+ * @throws IOException 创建 StringEntity 时可能抛出的 IO 异常
+ */
+ private void setupRequest (HttpPost httpPost, String requestBody) throws IOException {
+ // 创建 StringEntity 对象,用于封装请求体
+ StringEntity entity = new StringEntity(requestBody);
+ // 设置请求体
+ httpPost.setEntity(entity);
+ // 设置请求头,指定请求体的内容类型为 JSON
+ httpPost.setHeader("Content-Type", "application/json");
+ }
+
+ /**
+ * 处理响应实体
+ *
+ * @param response HttpResponse 对象
+ * @throws IOException 读取响应实体输入流时可能抛出的 IO 异常
+ */
+ private void handleResponseEntity (HttpResponse response, SseEmitter emitter) throws IOException {
+ // 获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+ if (responseEntity != null) {
+ // 使用 try-with-resources 语句自动关闭输入流和 BufferedReader
+ try (InputStream inputStream = responseEntity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line;
+ // 逐行读取响应内容并处理
+ while ((line = reader.readLine()) != null) {
+ System.out.println("接收到的响应行数据: " + line);
+ String content = parseStreamLine(line);
+ if (content != null) {
+ emitter.send(SseEmitter.event().data(content));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 解析流式返回的单行数据,提取有效内容并清理特定标记
+ *
+ * @param line 流式响应中的单行JSON数据
+ * @return 处理后的文本内容(若无有效内容返回null)
+ */
+ private String parseStreamLine (String line) {
+ if (StringUtils.isNotBlank(line)) {
+ if (line.startsWith("data: ")) {
+ String dataString = extractJsonFromDataString(line);
+ if (!dataString.contains("[DONE]")) {
+ JSONObject jsonObject = JSON.parseObject(dataString);
+ // 获取 choices 数组
+ JSONArray choicesArray = jsonObject.getJSONArray("choices");
+ if (choicesArray != null && !choicesArray.isEmpty()) {
+ // 获取第一个 choice 对象
+ JSONObject firstChoice = choicesArray.getJSONObject(0);
+ // 获取 delta 对象
+ JSONObject delta = firstChoice.getJSONObject("delta");
+ if (delta != null) {
+ // 获取 content 的值
+ String content = delta.getString("content");
+ return "{\"content\":\"" + content + "\",\"finish_reason\":\"" + false + "\"}";
+ }
+ }
+ } else {
+ return "{\"content\":\"" + "\",\"finish_reason\":\"" + true + "\"}";
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * 从包含 "data: " 前缀的字符串中提取 JSON 字符串
+ *
+ * @param input 包含 "data: " 前缀的原始字符串
+ * @return 提取出的 JSON 字符串,如果未找到 "data: " 则返回 null
+ */
+ public static String extractJsonFromDataString (String input) {
+ if (input == null) {
+ return null;
+ }
+ int index = input.indexOf("data: ");
+ if (index != -1) {
+ return input.substring(index + "data: ".length()).trim();
+ }
+ return null;
}
/**
@@ -254,4 +382,5 @@ public class ModelService {
}
return null;
}
+
}
diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/RagHttpService.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/RagHttpService.java
index 09ee4d04b..ac683ba3e 100644
--- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/RagHttpService.java
+++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/RagHttpService.java
@@ -415,24 +415,24 @@ public class RagHttpService {
Path tempFilePath = downloadFileToTemp(fileUrl, fileName);
log.info("文件已下载到临时目录: {}", tempFilePath);
- String fileSuffix = getFileSuffix(fileName);
- if ("doc".equals(fileSuffix)) {
- log.info("正在处理 doc 文件");
- try {
- tempFilePath= converterDocToDocx(tempFilePath.toString(), tempFilePath.toString().replace(".doc", ".docx"));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
+// String fileSuffix = getFileSuffix(fileName);
+// if ("doc".equals(fileSuffix)) {
+// log.info("正在处理 doc 文件");
+// try {
+// tempFilePath = converterDocToDocx(tempFilePath.toString(), tempFilePath.toString().replace(".doc", ".docx"));
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+// }
- if ("md".equals(fileSuffix)) {
- log.info("正在处理 md 文件");
- try {
- tempFilePath= converterMdToTxt(tempFilePath.toString(), tempFilePath.toString().replace(".md", ".docx"));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
+ // if ("md".equals(fileSuffix)) {
+ // log.info("正在处理 md 文件");
+ // try {
+ // tempFilePath= converterMdToTxt(tempFilePath.toString(), tempFilePath.toString().replace(".md", ".txt"));
+ // } catch (Exception e) {
+ // throw new RuntimeException(e);
+ // }
+ // }
// 创建 OkHttpClient 实例
log.info("创建 OkHttpClient 实例,设置超时时间为 3 分钟");
@@ -626,7 +626,7 @@ public class RagHttpService {
return path;
}
- public static Path converterDocToDocx(String inputPath, String outputPath) throws Exception {
+ public static Path converterDocToDocx (String inputPath, String outputPath) throws Exception {
// 读取DOC文档
try (HWPFDocument doc = new HWPFDocument(Files.newInputStream(Paths.get(inputPath)))) {
XWPFDocument docx = new XWPFDocument();
@@ -650,6 +650,7 @@ public class RagHttpService {
return Paths.get(outputPath);
}
}
+
/**
* 处理响应结果
*/
diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/ModelCompletionsReqVO.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/ModelCompletionsReqVO.java
index a4d212b70..f66e5ee46 100644
--- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/ModelCompletionsReqVO.java
+++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/ModelCompletionsReqVO.java
@@ -17,6 +17,9 @@ public class ModelCompletionsReqVO {
private List