|
|
@@ -1,13 +1,14 @@
|
|
|
package com.tzld.longarticle.recommend.server.remote;
|
|
|
|
|
|
-import cn.hutool.core.collection.CollectionUtil;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
-import com.tzld.longarticle.recommend.server.model.dto.kimi.KimiOfficialApiResponse;
|
|
|
-import com.tzld.longarticle.recommend.server.model.dto.kimi.KimiResult;
|
|
|
+import com.tzld.longarticle.recommend.server.common.enums.ApiChannelEnum;
|
|
|
+import com.tzld.longarticle.recommend.server.model.dto.kimi.AIOfficialApiResponse;
|
|
|
+import com.tzld.longarticle.recommend.server.model.dto.kimi.AIResult;
|
|
|
import com.tzld.longarticle.recommend.server.util.MapBuilder;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import okhttp3.*;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
import org.apache.http.util.TextUtils;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
@@ -26,6 +27,21 @@ public class DeepSeekApiService {
|
|
|
@Value("${deepseek.default.model:deepseek-v4-flash}")
|
|
|
private String defaultModel;
|
|
|
|
|
|
+ @Value("${deepseek.official.url:https://api.deepseek.com/chat/completions}")
|
|
|
+ private String officialUrl;
|
|
|
+
|
|
|
+ @Value("${deepseek.official.apiKey:sk-62d7b2c37f824735aa4985852c919c1f}")
|
|
|
+ private String officialApiKey;
|
|
|
+
|
|
|
+ @Value("${deepseek.volcengine.url:https://ark.cn-beijing.volces.com/api/v3/chat/completions}")
|
|
|
+ private String volcengineUrl;
|
|
|
+
|
|
|
+ @Value("${deepseek.volcengine.apiKey:ark-b5d6fcbb-14f9-4f70-a92d-605ec6a72c8d-40883}")
|
|
|
+ private String volcengineApiKey;
|
|
|
+
|
|
|
+ @Value("${deepseek.volcengine.model:ep-20250717193758-8gvmz}")
|
|
|
+ private String volcengineModel;
|
|
|
+
|
|
|
@PostConstruct
|
|
|
public void init() {
|
|
|
client = new OkHttpClient().newBuilder()
|
|
|
@@ -35,14 +51,46 @@ public class DeepSeekApiService {
|
|
|
.build();
|
|
|
}
|
|
|
|
|
|
- public KimiResult requestOfficialApi(String prompt, String model, Double temperature, Boolean isJSON) {
|
|
|
- KimiResult result = new KimiResult();
|
|
|
+ /**
|
|
|
+ * 默认调用火山引擎 API
|
|
|
+ */
|
|
|
+ public AIResult request(String prompt, String model, Double temperature, Boolean isJSON) {
|
|
|
+ return request(prompt, model, temperature, isJSON, ApiChannelEnum.VOLCENGINE);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支持指定渠道的 API 调用
|
|
|
+ */
|
|
|
+ public AIResult request(String prompt, String model, Double temperature, Boolean isJSON, ApiChannelEnum channel) {
|
|
|
+ AIResult result = new AIResult();
|
|
|
result.setSuccess(false);
|
|
|
if (TextUtils.isBlank(prompt) || TextUtils.isBlank(prompt.trim())) {
|
|
|
result.setFailReason("prompt is empty");
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ String url;
|
|
|
+ String apiKey;
|
|
|
+ String defaultChannelModel;
|
|
|
+ String channelName;
|
|
|
+
|
|
|
+ if (channel == ApiChannelEnum.OFFICIAL) {
|
|
|
+ url = officialUrl;
|
|
|
+ apiKey = officialApiKey;
|
|
|
+ defaultChannelModel = defaultModel;
|
|
|
+ channelName = "official";
|
|
|
+ } else {
|
|
|
+ url = volcengineUrl;
|
|
|
+ apiKey = volcengineApiKey;
|
|
|
+ defaultChannelModel = volcengineModel;
|
|
|
+ channelName = "volcengine";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (TextUtils.isBlank(apiKey)) {
|
|
|
+ result.setFailReason(channelName + " apiKey is not configured");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
try {
|
|
|
JSONArray jsonArray = new JSONArray();
|
|
|
JSONObject message = new JSONObject();
|
|
|
@@ -50,9 +98,15 @@ public class DeepSeekApiService {
|
|
|
message.put("content", prompt);
|
|
|
jsonArray.add(message);
|
|
|
|
|
|
+ String useModel = Optional.ofNullable(model).orElse(defaultChannelModel);
|
|
|
+ if (TextUtils.isBlank(useModel)) {
|
|
|
+ result.setFailReason("model is empty");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
Map<Object, Object> bodyParam = MapBuilder
|
|
|
.builder()
|
|
|
- .put("model", Optional.ofNullable(model).orElse(defaultModel))
|
|
|
+ .put("model", useModel)
|
|
|
.put("temperature", Optional.ofNullable(temperature).orElse(0.3))
|
|
|
.put("messages", jsonArray)
|
|
|
.build();
|
|
|
@@ -65,20 +119,20 @@ public class DeepSeekApiService {
|
|
|
MediaType mediaType = MediaType.parse("application/json");
|
|
|
RequestBody body = RequestBody.create(mediaType, JSONObject.toJSONString(bodyParam));
|
|
|
Request request = new Request.Builder()
|
|
|
- .url("https://api.deepseek.com/chat/completions")
|
|
|
+ .url(url)
|
|
|
.method("POST", body)
|
|
|
.addHeader("Content-Type", "application/json")
|
|
|
.addHeader("Accept", "application/json")
|
|
|
- .addHeader("Authorization", "Bearer sk-717db6bbb4924f92b3b4da6fd2312d55")
|
|
|
+ .addHeader("Authorization", "Bearer " + apiKey)
|
|
|
.build();
|
|
|
Response response = client.newCall(request).execute();
|
|
|
|
|
|
String responseContent = response.body().string();
|
|
|
result.setResponseStr(responseContent);
|
|
|
- log.info("deepseek api responseContent = {}", responseContent);
|
|
|
+ log.info("deepseek {} api responseContent = {}", channelName, responseContent);
|
|
|
if (response.isSuccessful()) {
|
|
|
- KimiOfficialApiResponse obj = JSONObject.parseObject(responseContent, KimiOfficialApiResponse.class);
|
|
|
- if (CollectionUtil.isNotEmpty(obj.getChoices())) {
|
|
|
+ AIOfficialApiResponse obj = JSONObject.parseObject(responseContent, AIOfficialApiResponse.class);
|
|
|
+ if (CollectionUtils.isNotEmpty(obj.getChoices())) {
|
|
|
result.setSuccess(true);
|
|
|
result.setResponse(obj);
|
|
|
} else {
|
|
|
@@ -89,9 +143,16 @@ public class DeepSeekApiService {
|
|
|
result.setFailReason("request error code:" + response.code() + " message:" + json.getString("error"));
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- log.error("deepseek official api fail: " + e.getMessage());
|
|
|
+ log.error("deepseek {} api fail: {}", channelName, e.getMessage());
|
|
|
result.setFailReason(e.getMessage());
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 调用 DeepSeek 官方 API(向后兼容)
|
|
|
+ */
|
|
|
+ public AIResult requestOfficialApi(String prompt, String model, Double temperature, Boolean isJSON) {
|
|
|
+ return request(prompt, model, temperature, isJSON, ApiChannelEnum.OFFICIAL);
|
|
|
+ }
|
|
|
}
|