package cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
/**
* 讯飞星火 {@link ChatModel} 实现类
*
* @author fansili
*/
@Slf4j
public class XingHuoChatModel implements ChatModel {
/**
* 星火 X2
*
* @see 接口地址
*/
public static final String MODEL_X2 = "x2";
/**
* 星火 X2 Flash
*
* @see 接口地址
*/
public static final String MODEL_X2_FLASH = "x2-flash";
private static final String BASE_URL_X2 = "https://spark-api-open.xf-yun.com/x2";
private static final String BASE_URL_X2_FLASH = "https://spark-api-open.xf-yun.com/agent/v1";
public static final String MODEL_DEFAULT = MODEL_X2_FLASH;
private static String getBaseUrl(String model) {
if (MODEL_X2_FLASH.equals(model)) {
return BASE_URL_X2_FLASH;
}
return BASE_URL_X2;
}
private final String apiKey;
private final DeepSeekChatOptions options;
/**
* 兼容 OpenAI 接口,进行复用
*/
private final ChatModel chatModelX2;
private final ChatModel chatModelX2Flash;
private XingHuoChatModel(String apiKey, DeepSeekChatOptions options) {
this.apiKey = apiKey;
this.options = options;
this.chatModelX2 = buildChatModel(MODEL_X2);
this.chatModelX2Flash = buildChatModel(MODEL_X2_FLASH);
}
public static Builder builder() {
return new Builder();
}
@Override
public ChatResponse call(Prompt prompt) {
return getChatModel(prompt).call(buildApiPrompt(prompt));
}
@Override
public Flux stream(Prompt prompt) {
return getChatModel(prompt).stream(buildApiPrompt(prompt));
}
@Override
public ChatOptions getOptions() {
return options;
}
@Override
@Deprecated(forRemoval = true)
@SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
return getOptions();
}
private ChatModel getChatModel(Prompt prompt) {
String model = options.getModel();
ChatOptions options = prompt.getOptions();
if (options != null && isBusinessModel(options.getModel())) {
model = options.getModel();
}
return getChatModel(model);
}
private ChatModel getChatModel(String model) {
if (MODEL_X2_FLASH.equals(model)) {
return chatModelX2Flash;
}
return chatModelX2;
}
private ChatModel buildChatModel(String model) {
return DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(getBaseUrl(model))
.apiKey(apiKey)
.build())
.options(options.mutate().model("spark-x").build())
.build();
}
private static Prompt buildApiPrompt(Prompt prompt) {
ChatOptions options = prompt.getOptions();
if (options == null) {
return prompt;
}
return Prompt.builder()
.messages(prompt.getInstructions())
.chatOptions(options.mutate().model("spark-x").build())
.build();
}
private static boolean isBusinessModel(String model) {
return MODEL_X2.equals(model) || MODEL_X2_FLASH.equals(model);
}
public static final class Builder {
private String apiKey;
private DeepSeekChatOptions options;
public Builder apiKey(String apiKey) {
this.apiKey = apiKey;
return this;
}
public Builder options(DeepSeekChatOptions options) {
this.options = options;
return this;
}
public XingHuoChatModel build() {
DeepSeekChatOptions options = this.options != null ? this.options : DeepSeekChatOptions.builder().build();
if (StrUtil.isEmpty(options.getModel())) {
options = options.mutate().model(MODEL_DEFAULT).build();
}
return new XingHuoChatModel(apiKey, options);
}
}
}