This commit is contained in:
jack ning
2025-07-11 10:04:54 +08:00
parent c9d48887be
commit 78c338640a
8 changed files with 351 additions and 346 deletions

View File

@@ -284,14 +284,14 @@ services:
# https://bailian.console.aliyun.com/?spm=a2c4g.11186623.0.0.11c67980m5X2VR#/model-market
SPRING_AI_DASHSCOPE_BASE_URL: https://dashscope.aliyuncs.com/compatible-mode
SPRING_AI_DASHSCOPE_API_KEY: 'sk-xxx'
SPRING_AI_DASHSCOPE_CHAT_ENABLED: false
SPRING_AI_DASHSCOPE_CHAT_ENABLED: "false"
SPRING_AI_DASHSCOPE_CHAT_OPTIONS_MODEL: deepseek-r1
SPRING_AI_DASHSCOPE_CHAT_OPTIONS_TEMPERATURE: 0.7
SPRING_AI_DASHSCOPE_AUDIO_TRANSCRIPTION_ENABLED: false
SPRING_AI_DASHSCOPE_IMAGE_ENABLED: false
SPRING_AI_DASHSCOPE_EMBEDDING_ENABLED: false
SPRING_AI_DASHSCOPE_AUDIO_SYNTHESIS_ENABLED: false
SPRING_AI_NACOS_PROMPT_TEMPLATE_ENABLED: false
SPRING_AI_DASHSCOPE_AUDIO_TRANSCRIPTION_ENABLED: "false"
SPRING_AI_DASHSCOPE_IMAGE_ENABLED: "false"
SPRING_AI_DASHSCOPE_EMBEDDING_ENABLED: "false"
SPRING_AI_DASHSCOPE_AUDIO_SYNTHESIS_ENABLED: "false"
SPRING_AI_NACOS_PROMPT_TEMPLATE_ENABLED: "false"
# logging config
LOGGING_LEVEL_COM_BYTEDESK_AI: DEBUG
LOGGING_LEVEL_COM_BYTEDESK_CORE: DEBUG

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 KiB

After

Width:  |  Height:  |  Size: 478 KiB

View File

@@ -125,11 +125,11 @@
<!-- https://github.com/alibaba/spring-ai-alibaba -->
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud.ai/spring-ai-alibaba-starter-dashscope -->
<dependency>
<!-- <dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
</dependency> -->
<!-- ///////////////////////////////////////////////////////////////////////////// -->

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2025-02-17 11:17:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-11 09:08:46
* @LastEditTime: 2025-07-11 10:03:16
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -13,61 +13,61 @@
*/
package com.bytedesk.ai.springai.providers.dashscope;
// import org.springframework.ai.chat.client.ChatClient;
// import org.springframework.ai.openai.OpenAiChatModel;
// import org.springframework.ai.openai.OpenAiChatOptions;
// import org.springframework.ai.openai.api.OpenAiApi;
// import org.springframework.beans.factory.annotation.Value;
// import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
// import org.springframework.context.annotation.Bean;
// import org.springframework.context.annotation.Configuration;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// @Configuration
// @ConditionalOnProperty(name = "spring.ai.dashscope.chat.enabled", havingValue = "true", matchIfMissing = false)
// public class SpringAIDashscopeConfig {
@Configuration
@ConditionalOnProperty(name = "spring.ai.dashscope.chat.enabled", havingValue = "true", matchIfMissing = false)
public class SpringAIDashscopeConfig {
// @Value("${spring.ai.dashscope.base-url:https://dashscope.aliyuncs.com/compatible-mode}")
// private String baseUrl;
@Value("${spring.ai.dashscope.base-url:https://dashscope.aliyuncs.com/compatible-mode}")
private String baseUrl;
// @Value("${spring.ai.dashscope.api-key:sk-xxx}")
// private String apiKey;
@Value("${spring.ai.dashscope.api-key:sk-xxx}")
private String apiKey;
// @Value("${spring.ai.dashscope.chat.options.model:deepseek-r1}")
// private String model;
@Value("${spring.ai.dashscope.chat.options.model:deepseek-r1}")
private String model;
// @Value("${spring.ai.dashscope.chat.options.temperature:0.7}")
// private Double temperature;
@Value("${spring.ai.dashscope.chat.options.temperature:0.7}")
private Double temperature;
// @Bean("dashscopeApi")
// OpenAiApi dashscopeApi() {
// return OpenAiApi.builder()
// .baseUrl(baseUrl)
// .apiKey(apiKey)
// .build();
// }
@Bean("dashscopeApi")
OpenAiApi dashscopeApi() {
return OpenAiApi.builder()
.baseUrl(baseUrl)
.apiKey(apiKey)
.build();
}
// @Bean("dashscopeChatOptions")
// OpenAiChatOptions dashscopeChatOptions() {
// return OpenAiChatOptions.builder()
// .model(model)
// .temperature(temperature)
// .build();
// }
@Bean("dashscopeChatOptions")
OpenAiChatOptions dashscopeChatOptions() {
return OpenAiChatOptions.builder()
.model(model)
.temperature(temperature)
.build();
}
// @Bean("dashscopeChatModel")
// OpenAiChatModel dashscopeChatModel() {
// return OpenAiChatModel.builder()
// .openAiApi(dashscopeApi())
// .defaultOptions(dashscopeChatOptions())
// .build();
// }
@Bean("dashscopeChatModel")
OpenAiChatModel dashscopeChatModel() {
return OpenAiChatModel.builder()
.openAiApi(dashscopeApi())
.defaultOptions(dashscopeChatOptions())
.build();
}
// @Bean("dashscopeChatClient")
// ChatClient dashscopeChatClient() {
// return ChatClient.builder(dashscopeChatModel())
// .defaultOptions(dashscopeChatOptions())
// .build();
// }
@Bean("dashscopeChatClient")
ChatClient dashscopeChatClient() {
return ChatClient.builder(dashscopeChatModel())
.defaultOptions(dashscopeChatOptions())
.build();
}
// }
}

View File

@@ -13,136 +13,136 @@
*/
package com.bytedesk.ai.springai.providers.dashscope;
// import java.util.concurrent.ExecutorService;
// import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// import org.springframework.ai.chat.messages.UserMessage;
// import org.springframework.ai.chat.model.ChatResponse;
// import org.springframework.ai.chat.prompt.Prompt;
// import org.springframework.ai.openai.OpenAiChatModel;
// import org.springframework.ai.openai.OpenAiChatOptions;
// import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
// import org.springframework.http.MediaType;
// import org.springframework.http.ResponseEntity;
// import org.springframework.web.bind.annotation.GetMapping;
// import org.springframework.web.bind.annotation.RequestMapping;
// import org.springframework.web.bind.annotation.RequestParam;
// import org.springframework.web.bind.annotation.RestController;
// import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
// import com.bytedesk.core.utils.JsonResult;
import com.bytedesk.core.utils.JsonResult;
// import lombok.RequiredArgsConstructor;
// import lombok.extern.slf4j.Slf4j;
// import reactor.core.publisher.Flux;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
// /**
// * DeepSeek接口
// */
// @Slf4j
// @RestController
// @RequestMapping("/springai/dashscope")
// @RequiredArgsConstructor
// @ConditionalOnProperty(name = "spring.ai.dashscope.chat.enabled", havingValue = "true", matchIfMissing = false)
// public class SpringAIDashscopeController {
/**
* DeepSeek接口
*/
@Slf4j
@RestController
@RequestMapping("/springai/dashscope")
@RequiredArgsConstructor
@ConditionalOnProperty(name = "spring.ai.dashscope.chat.enabled", havingValue = "true", matchIfMissing = false)
public class SpringAIDashscopeController {
// private final SpringAIDashscopeService springAIDashscopeService;
// private final ExecutorService executorService = Executors.newCachedThreadPool();
private final SpringAIDashscopeService springAIDashscopeService;
private final ExecutorService executorService = Executors.newCachedThreadPool();
// /**
// * 方式1同步调用
// * http://127.0.0.1:9003/springai/dashscope/chat/sync?message=hello
// */
// @GetMapping("/chat/sync")
// public ResponseEntity<JsonResult<?>> chatSync(
// @RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
// String response = springAIDashscopeService.processPromptSync(message, null);
// return ResponseEntity.ok(JsonResult.success(response));
// }
/**
* 方式1同步调用
* http://127.0.0.1:9003/springai/dashscope/chat/sync?message=hello
*/
@GetMapping("/chat/sync")
public ResponseEntity<JsonResult<?>> chatSync(
@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
String response = springAIDashscopeService.processPromptSync(message, null);
return ResponseEntity.ok(JsonResult.success(response));
}
// /**
// * 方式2异步流式调用
// * http://127.0.0.1:9003/springai/dashscope/chat/stream?message=hello
// */
// @GetMapping("/chat/stream")
// public Flux<ChatResponse> chatStream(
// @RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
// Prompt prompt = new Prompt(new UserMessage(message));
// OpenAiChatModel model = springAIDashscopeService.getChatModel();
// if (model != null) {
// return model.stream(prompt);
// } else {
// return Flux.empty();
// }
// }
/**
* 方式2异步流式调用
* http://127.0.0.1:9003/springai/dashscope/chat/stream?message=hello
*/
@GetMapping("/chat/stream")
public Flux<ChatResponse> chatStream(
@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
OpenAiChatModel model = springAIDashscopeService.getChatModel();
if (model != null) {
return model.stream(prompt);
} else {
return Flux.empty();
}
}
// /**
// * 方式3SSE调用
// * http://127.0.0.1:9003/springai/dashscope/chat/sse?message=hello
// */
// @GetMapping(value = "/chat/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
// public SseEmitter chatSSE(
// @RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
/**
* 方式3SSE调用
* http://127.0.0.1:9003/springai/dashscope/chat/sse?message=hello
*/
@GetMapping(value = "/chat/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chatSSE(
@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
// SseEmitter emitter = new SseEmitter(180_000L); // 3分钟超时
SseEmitter emitter = new SseEmitter(180_000L); // 3分钟超时
// executorService.execute(() -> {
// try {
// // springAIDashscopeService.processPromptSSE(message, emitter);
// } catch (Exception e) {
// log.error("Error processing SSE request", e);
// emitter.completeWithError(e);
// }
// });
executorService.execute(() -> {
try {
// springAIDashscopeService.processPromptSSE(message, emitter);
} catch (Exception e) {
log.error("Error processing SSE request", e);
emitter.completeWithError(e);
}
});
// // 添加超时和完成时的回调
// emitter.onTimeout(() -> {
// log.warn("SSE connection timed out");
// emitter.complete();
// });
// 添加超时和完成时的回调
emitter.onTimeout(() -> {
log.warn("SSE connection timed out");
emitter.complete();
});
// emitter.onCompletion(() -> {
// log.info("SSE connection completed");
// });
emitter.onCompletion(() -> {
log.info("SSE connection completed");
});
// return emitter;
// }
return emitter;
}
// /**
// * 自定义模型参数的调用示例
// * http://127.0.0.1:9003/springai/dashscope/chat/custom?message=hello
// */
// @GetMapping("/chat/custom")
// public ResponseEntity<?> chatCustom(
// @RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
/**
* 自定义模型参数的调用示例
* http://127.0.0.1:9003/springai/dashscope/chat/custom?message=hello
*/
@GetMapping("/chat/custom")
public ResponseEntity<?> chatCustom(
@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
// OpenAiChatModel model = springAIDashscopeService.getChatModel();
// if (model == null) {
// return ResponseEntity.ok(JsonResult.error("DeepSeek service is not available"));
// }
OpenAiChatModel model = springAIDashscopeService.getChatModel();
if (model == null) {
return ResponseEntity.ok(JsonResult.error("DeepSeek service is not available"));
}
// try {
// ChatResponse response = model.call(
// new Prompt(
// message,
// OpenAiChatOptions.builder()
// .model("dashscope-chat")
// .temperature(0.7)
// .topP(0.9)
// .build()
// ));
try {
ChatResponse response = model.call(
new Prompt(
message,
OpenAiChatOptions.builder()
.model("dashscope-chat")
.temperature(0.7)
.topP(0.9)
.build()
));
// String result = response.getResult().getOutput().getText();
// return ResponseEntity.ok(JsonResult.success(result));
// } catch (Exception e) {
// return ResponseEntity.ok(JsonResult.error(e.getMessage()));
// }
// }
String result = response.getResult().getOutput().getText();
return ResponseEntity.ok(JsonResult.success(result));
} catch (Exception e) {
return ResponseEntity.ok(JsonResult.error(e.getMessage()));
}
}
// // 在 Bean 销毁时关闭线程池
// public void destroy() {
// if (executorService != null && !executorService.isShutdown()) {
// executorService.shutdown();
// }
// }
// }
// 在 Bean 销毁时关闭线程池
public void destroy() {
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
}
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2025-02-28 11:44:03
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-11 09:08:55
* @LastEditTime: 2025-07-11 10:03:26
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -13,190 +13,190 @@
*/
package com.bytedesk.ai.springai.providers.dashscope;
// import java.util.List;
import java.util.List;
// import org.springframework.ai.chat.messages.AssistantMessage;
// import org.springframework.ai.chat.model.Generation;
// import org.springframework.ai.chat.prompt.Prompt;
// import org.springframework.ai.openai.OpenAiChatModel;
// import org.springframework.ai.openai.OpenAiChatOptions;
// import org.springframework.beans.factory.annotation.Autowired;
// import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
// import org.springframework.stereotype.Service;
// import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
// import com.bytedesk.ai.robot.RobotLlm;
// import com.bytedesk.ai.robot.RobotProtobuf;
// import com.bytedesk.ai.springai.service.BaseSpringAIService;
// import com.bytedesk.core.message.MessageProtobuf;
// import com.bytedesk.core.message.MessageTypeEnum;
import com.bytedesk.ai.robot.RobotLlm;
import com.bytedesk.ai.robot.RobotProtobuf;
import com.bytedesk.ai.springai.service.BaseSpringAIService;
import com.bytedesk.core.message.MessageProtobuf;
import com.bytedesk.core.message.MessageTypeEnum;
// import lombok.extern.slf4j.Slf4j;
import lombok.extern.slf4j.Slf4j;
// @Slf4j
// @Service
// @ConditionalOnProperty(name = "spring.ai.dashscope.chat.enabled", havingValue = "true", matchIfMissing = false)
// public class SpringAIDashscopeService extends BaseSpringAIService {
@Slf4j
@Service
@ConditionalOnProperty(name = "spring.ai.dashscope.chat.enabled", havingValue = "true", matchIfMissing = false)
public class SpringAIDashscopeService extends BaseSpringAIService {
// @Autowired(required = false)
// private OpenAiChatModel dashscopeChatModel;
@Autowired(required = false)
private OpenAiChatModel dashscopeChatModel;
// public SpringAIDashscopeService() {
// super(); // 调用基类的无参构造函数
// }
public SpringAIDashscopeService() {
super(); // 调用基类的无参构造函数
}
// /**
// * 根据机器人配置创建动态的OpenAiChatOptions
// *
// * @param llm 机器人LLM配置
// * @return 根据机器人配置创建的选项
// */
// private OpenAiChatOptions createDynamicOptions(RobotLlm llm) {
// return super.createDynamicOptions(llm, robotLlm ->
// OpenAiChatOptions.builder()
// .model(robotLlm.getModel())
// .temperature(robotLlm.getTemperature())
// .topP(robotLlm.getTopP())
// .build()
// );
// }
/**
* 根据机器人配置创建动态的OpenAiChatOptions
*
* @param llm 机器人LLM配置
* @return 根据机器人配置创建的选项
*/
private OpenAiChatOptions createDynamicOptions(RobotLlm llm) {
return super.createDynamicOptions(llm, robotLlm ->
OpenAiChatOptions.builder()
.model(robotLlm.getModel())
.temperature(robotLlm.getTemperature())
.topP(robotLlm.getTopP())
.build()
);
}
// @Override
// protected void processPromptWebsocket(Prompt prompt, RobotProtobuf robot, MessageProtobuf messageProtobufQuery, MessageProtobuf messageProtobufReply) {
// // 从robot中获取llm配置
// RobotLlm llm = robot.getLlm();
@Override
protected void processPromptWebsocket(Prompt prompt, RobotProtobuf robot, MessageProtobuf messageProtobufQuery, MessageProtobuf messageProtobufReply) {
// 从robot中获取llm配置
RobotLlm llm = robot.getLlm();
// if (dashscopeChatModel == null) {
// sendMessageWebsocket(MessageTypeEnum.ERROR, "Dashscope服务不可用", messageProtobufReply);
// return;
// }
if (dashscopeChatModel == null) {
sendMessageWebsocket(MessageTypeEnum.ERROR, "Dashscope服务不可用", messageProtobufReply);
return;
}
// // 如果有自定义选项创建新的Prompt
// Prompt requestPrompt = prompt;
// OpenAiChatOptions customOptions = createDynamicOptions(llm);
// if (customOptions != null) {
// requestPrompt = new Prompt(prompt.getInstructions(), customOptions);
// }
// 如果有自定义选项创建新的Prompt
Prompt requestPrompt = prompt;
OpenAiChatOptions customOptions = createDynamicOptions(llm);
if (customOptions != null) {
requestPrompt = new Prompt(prompt.getInstructions(), customOptions);
}
// // 使用同一个ChatModel实例但传入不同的选项
// dashscopeChatModel.stream(requestPrompt).subscribe(
// response -> {
// if (response != null) {
// log.info("Dashscope API response metadata: {}", response.getMetadata());
// List<Generation> generations = response.getResults();
// for (Generation generation : generations) {
// AssistantMessage assistantMessage = generation.getOutput();
// String textContent = assistantMessage.getText();
// 使用同一个ChatModel实例但传入不同的选项
dashscopeChatModel.stream(requestPrompt).subscribe(
response -> {
if (response != null) {
log.info("Dashscope API response metadata: {}", response.getMetadata());
List<Generation> generations = response.getResults();
for (Generation generation : generations) {
AssistantMessage assistantMessage = generation.getOutput();
String textContent = assistantMessage.getText();
// sendMessageWebsocket(MessageTypeEnum.STREAM, textContent, messageProtobufReply);
// }
// }
// },
// error -> {
// log.error("Dashscope API error: ", error);
// sendMessageWebsocket(MessageTypeEnum.ERROR, "服务暂时不可用,请稍后重试", messageProtobufReply);
// },
// () -> {
// log.info("Chat stream completed");
// });
// }
sendMessageWebsocket(MessageTypeEnum.STREAM, textContent, messageProtobufReply);
}
}
},
error -> {
log.error("Dashscope API error: ", error);
sendMessageWebsocket(MessageTypeEnum.ERROR, "服务暂时不可用,请稍后重试", messageProtobufReply);
},
() -> {
log.info("Chat stream completed");
});
}
// @Override
// protected String processPromptSync(String message, RobotProtobuf robot) {
// try {
// if (dashscopeChatModel == null) {
// return "Dashscope service is not available";
// }
@Override
protected String processPromptSync(String message, RobotProtobuf robot) {
try {
if (dashscopeChatModel == null) {
return "Dashscope service is not available";
}
// try {
// // 如果有robot参数尝试创建自定义选项
// if (robot != null && robot.getLlm() != null) {
// // 创建自定义选项
// OpenAiChatOptions customOptions = createDynamicOptions(robot.getLlm());
// if (customOptions != null) {
// // 使用自定义选项创建Prompt
// Prompt prompt = new Prompt(message, customOptions);
// var response = dashscopeChatModel.call(prompt);
// return extractTextFromResponse(response);
// }
// }
try {
// 如果有robot参数尝试创建自定义选项
if (robot != null && robot.getLlm() != null) {
// 创建自定义选项
OpenAiChatOptions customOptions = createDynamicOptions(robot.getLlm());
if (customOptions != null) {
// 使用自定义选项创建Prompt
Prompt prompt = new Prompt(message, customOptions);
var response = dashscopeChatModel.call(prompt);
return extractTextFromResponse(response);
}
}
// var response = dashscopeChatModel.call(message);
// return extractTextFromResponse(response);
// } catch (Exception e) {
// log.error("Dashscope API call error: ", e);
// return "服务暂时不可用,请稍后重试";
// }
// } catch (Exception e) {
// log.error("Dashscope API sync error: ", e);
// return "服务暂时不可用,请稍后重试";
// }
// }
var response = dashscopeChatModel.call(message);
return extractTextFromResponse(response);
} catch (Exception e) {
log.error("Dashscope API call error: ", e);
return "服务暂时不可用,请稍后重试";
}
} catch (Exception e) {
log.error("Dashscope API sync error: ", e);
return "服务暂时不可用,请稍后重试";
}
}
// @Override
// protected void processPromptSse(Prompt prompt, RobotProtobuf robot, MessageProtobuf messageProtobufQuery, MessageProtobuf messageProtobufReply, SseEmitter emitter) {
// // 从robot中获取llm配置
// RobotLlm llm = robot.getLlm();
@Override
protected void processPromptSse(Prompt prompt, RobotProtobuf robot, MessageProtobuf messageProtobufQuery, MessageProtobuf messageProtobufReply, SseEmitter emitter) {
// 从robot中获取llm配置
RobotLlm llm = robot.getLlm();
// if (dashscopeChatModel == null) {
// handleSseError(new RuntimeException("Dashscope service not available"), messageProtobufQuery, messageProtobufReply, emitter);
// return;
// }
if (dashscopeChatModel == null) {
handleSseError(new RuntimeException("Dashscope service not available"), messageProtobufQuery, messageProtobufReply, emitter);
return;
}
// // 发送起始消息
// sendStreamStartMessage(messageProtobufReply, emitter, "正在思考中...");
// 发送起始消息
sendStreamStartMessage(messageProtobufReply, emitter, "正在思考中...");
// // 如果有自定义选项创建新的Prompt
// Prompt requestPrompt = prompt;
// OpenAiChatOptions customOptions = createDynamicOptions(llm);
// if (customOptions != null) {
// requestPrompt = new Prompt(prompt.getInstructions(), customOptions);
// }
// 如果有自定义选项创建新的Prompt
Prompt requestPrompt = prompt;
OpenAiChatOptions customOptions = createDynamicOptions(llm);
if (customOptions != null) {
requestPrompt = new Prompt(prompt.getInstructions(), customOptions);
}
// dashscopeChatModel.stream(requestPrompt).subscribe(
// response -> {
// try {
// if (response != null) {
// List<Generation> generations = response.getResults();
// for (Generation generation : generations) {
// AssistantMessage assistantMessage = generation.getOutput();
// String textContent = assistantMessage.getText();
// log.info("Dashscope API response metadata: {}, text {}",
// response.getMetadata(), textContent);
dashscopeChatModel.stream(requestPrompt).subscribe(
response -> {
try {
if (response != null) {
List<Generation> generations = response.getResults();
for (Generation generation : generations) {
AssistantMessage assistantMessage = generation.getOutput();
String textContent = assistantMessage.getText();
log.info("Dashscope API response metadata: {}, text {}",
response.getMetadata(), textContent);
// sendStreamMessage(messageProtobufQuery, messageProtobufReply, emitter, textContent);
// }
// }
// } catch (Exception e) {
// log.error("Error sending SSE event", e);
// handleSseError(e, messageProtobufQuery, messageProtobufReply, emitter);
// }
// },
// error -> {
// log.error("Dashscope API SSE error: ", error);
// handleSseError(error, messageProtobufQuery, messageProtobufReply, emitter);
// },
// () -> {
// log.info("Dashscope API SSE complete");
// sendStreamEndMessage(messageProtobufQuery, messageProtobufReply, emitter);
// });
// }
sendStreamMessage(messageProtobufQuery, messageProtobufReply, emitter, textContent);
}
}
} catch (Exception e) {
log.error("Error sending SSE event", e);
handleSseError(e, messageProtobufQuery, messageProtobufReply, emitter);
}
},
error -> {
log.error("Dashscope API SSE error: ", error);
handleSseError(error, messageProtobufQuery, messageProtobufReply, emitter);
},
() -> {
log.info("Dashscope API SSE complete");
sendStreamEndMessage(messageProtobufQuery, messageProtobufReply, emitter);
});
}
// public OpenAiChatModel getChatModel() {
// return dashscopeChatModel;
// }
public OpenAiChatModel getChatModel() {
return dashscopeChatModel;
}
// public Boolean isServiceHealthy() {
// if (dashscopeChatModel == null) {
// return false;
// }
public Boolean isServiceHealthy() {
if (dashscopeChatModel == null) {
return false;
}
// try {
// String response = processPromptSync("test", null);
// return !response.contains("不可用") && !response.equals("Dashscope service is not available");
// } catch (Exception e) {
// log.error("Error checking Dashscope service health", e);
// return false;
// }
// }
// }
try {
String response = processPromptSync("test", null);
return !response.contains("不可用") && !response.equals("Dashscope service is not available");
} catch (Exception e) {
log.error("Error checking Dashscope service health", e);
return false;
}
}
}

View File

@@ -35,7 +35,6 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Data
@Configuration
@ConditionalOnProperty(prefix = "spring.ai.ollama.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
public class SpringAIOllamaConfig {
@Value("${spring.ai.ollama.base-url:http://host.docker.internal:11434}")
@@ -61,6 +60,7 @@ public class SpringAIOllamaConfig {
}
@Bean("bytedeskOllamaChatOptions")
@ConditionalOnProperty(prefix = "spring.ai.ollama.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
OllamaOptions bytedeskOllamaChatOptions() {
return OllamaOptions.builder()
.model(ollamaChatOptionsModel)
@@ -72,6 +72,7 @@ public class SpringAIOllamaConfig {
}
@Bean("bytedeskOllamaEmbeddingOptions")
@ConditionalOnProperty(prefix = "spring.ai.ollama.embedding", name = "enabled", havingValue = "true", matchIfMissing = false)
OllamaOptions bytedeskOllamaEmbeddingOptions() {
return OllamaOptions.builder()
.model(ollamaEmbeddingOptionsModel)
@@ -80,6 +81,7 @@ public class SpringAIOllamaConfig {
@Primary
@Bean("bytedeskOllamaChatModel")
@ConditionalOnProperty(prefix = "spring.ai.ollama.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
OllamaChatModel bytedeskOllamaChatModel() {
return OllamaChatModel.builder()
.ollamaApi(bytedeskOllamaApi())
@@ -99,6 +101,7 @@ public class SpringAIOllamaConfig {
// https://docs.spring.io/spring-ai/reference/api/chatclient.html
@Primary
@Bean("bytedeskOllamaChatClient")
@ConditionalOnProperty(prefix = "spring.ai.ollama.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ChatClient bytedeskOllamaChatClient() {
return ChatClient.builder(bytedeskOllamaChatModel())
// .defaultSystem("You are a friendly chat bot that answers question in the voice of a {voice}")

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-31 10:53:11
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-04-17 14:44:29
* @LastEditTime: 2025-07-11 09:46:54
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import lombok.Data;
/**
@@ -37,7 +38,6 @@ import lombok.Data;
*/
@Data
@Configuration
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
public class SpringAIZhipuaiConfig {
@Value("${spring.ai.zhipuai.api-key:}")
@@ -58,6 +58,7 @@ public class SpringAIZhipuaiConfig {
}
@Bean("bytedeskZhipuaiChatOptions")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ZhiPuAiChatOptions bytedeskZhipuaiChatOptions() {
return ZhiPuAiChatOptions.builder()
.model(zhipuaiApiModel)
@@ -68,6 +69,7 @@ public class SpringAIZhipuaiConfig {
// https://docs.spring.io/spring-ai/reference/api/embeddings/zhipuai-embeddings.html
// https://open.bigmodel.cn/overview
@Bean("bytedeskZhipuaiEmbeddingOptions")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.embedding", name = "enabled", havingValue = "true", matchIfMissing = false)
ZhiPuAiEmbeddingOptions bytedeskZhipuaiEmbeddingOptions() {
return ZhiPuAiEmbeddingOptions.builder()
.model(zhipuaiEmbeddingModel)
@@ -76,28 +78,26 @@ public class SpringAIZhipuaiConfig {
// https://open.bigmodel.cn/dev/api/normal-model/glm-4
@Bean("bytedeskZhipuaiChatModel")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ZhiPuAiChatModel bytedeskZhipuaiChatModel() {
return new ZhiPuAiChatModel(bytedeskZhipuaiApi(), bytedeskZhipuaiChatOptions());
}
@Bean("bytedeskZhipuaiEmbeddingModel")
@Primary
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.embedding", name = "enabled", havingValue = "true", matchIfMissing = false)
ZhiPuAiEmbeddingModel bytedeskZhipuaiEmbeddingModel(org.springframework.core.env.Environment env) {
// Only mark as @Primary if this is the selected embedding provider
boolean isPrimary = "zhipuai".equals(env.getProperty("spring.ai.model.embedding"));
ZhiPuAiEmbeddingModel model = new ZhiPuAiEmbeddingModel(bytedeskZhipuaiApi(), MetadataMode.EMBED, bytedeskZhipuaiEmbeddingOptions());
if (isPrimary) {
// Use a proxy or custom annotation processor if needed, or document that only one embedding should be enabled
}
return model;
ZhiPuAiEmbeddingModel bytedeskZhipuaiEmbeddingModel() {
return new ZhiPuAiEmbeddingModel(bytedeskZhipuaiApi(), MetadataMode.EMBED, bytedeskZhipuaiEmbeddingOptions());
}
@Bean("bytedeskZhipuaiChatClientBuilder")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ChatClient.Builder bytedeskZhipuaiChatClientBuilder() {
return ChatClient.builder(bytedeskZhipuaiChatModel());
}
@Bean("bytedeskZhipuaiChatClient")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ChatClient bytedeskZhipuaiChatClient() {
return bytedeskZhipuaiChatClientBuilder()
.defaultOptions(bytedeskZhipuaiChatOptions())
@@ -105,11 +105,13 @@ public class SpringAIZhipuaiConfig {
}
@Bean("bytedeskZhipuaiImageApi")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ZhiPuAiImageApi bytedeskZhipuaiImageApi() {
return new ZhiPuAiImageApi(zhipuaiApiKey);
}
@Bean("bytedeskZhipuaiImageModel")
@ConditionalOnProperty(prefix = "spring.ai.zhipuai.chat", name = "enabled", havingValue = "true", matchIfMissing = false)
ZhiPuAiImageModel bytedeskZhipuaiImageModel() {
return new ZhiPuAiImageModel(bytedeskZhipuaiImageApi());
}