Kaynağa Gözat

接入火山引擎deepseek

wangyunpeng 1 hafta önce
ebeveyn
işleme
69c65c3958

+ 22 - 0
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/common/enums/ApiChannelEnum.java

@@ -0,0 +1,22 @@
+package com.tzld.longarticle.recommend.server.common.enums;
+
+public enum ApiChannelEnum {
+    OFFICIAL("official", "DeepSeek 官方 API"),
+    VOLCENGINE("volcengine", "火山引擎方舟 API");
+
+    private final String code;
+    private final String desc;
+
+    ApiChannelEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 1 - 1
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/model/dto/kimi/KimiOfficialApiResponse.java → long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/model/dto/kimi/AIOfficialApiResponse.java

@@ -5,7 +5,7 @@ import lombok.Data;
 import java.util.List;
 
 @Data
-public class KimiOfficialApiResponse {
+public class AIOfficialApiResponse {
 
     private String id;
     private String object;

+ 2 - 2
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/model/dto/kimi/KimiResult.java → long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/model/dto/kimi/AIResult.java

@@ -3,9 +3,9 @@ package com.tzld.longarticle.recommend.server.model.dto.kimi;
 import lombok.Data;
 
 @Data
-public class KimiResult {
+public class AIResult {
     private boolean success;
-    private KimiOfficialApiResponse response;
+    private AIOfficialApiResponse response;
     private String failReason;
     private String responseStr;
 }

+ 73 - 12
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/remote/DeepSeekApiService.java

@@ -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);
+    }
 }

+ 5 - 5
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/remote/KimiApiService.java

@@ -3,8 +3,8 @@ 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.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.*;
@@ -33,8 +33,8 @@ public class KimiApiService {
     }
 
 
-    public KimiResult requestOfficialApi(String prompt, String model, Double temperature, Boolean isJSON) {
-        KimiResult result = new KimiResult();
+    public AIResult requestOfficialApi(String prompt, String model, Double temperature, Boolean isJSON) {
+        AIResult result = new AIResult();
         result.setSuccess(false);
         if (TextUtils.isBlank(prompt) || TextUtils.isBlank(prompt.trim())) {
             result.setFailReason("prompt is empty");
@@ -74,7 +74,7 @@ public class KimiApiService {
             result.setResponseStr(responseContent);
             log.info("kimi api responseContent = {}", responseContent);
             if (response.isSuccessful()) {
-                KimiOfficialApiResponse obj = JSONObject.parseObject(responseContent, KimiOfficialApiResponse.class);
+                AIOfficialApiResponse obj = JSONObject.parseObject(responseContent, AIOfficialApiResponse.class);
                 if (CollectionUtil.isNotEmpty(obj.getChoices())) {
                     result.setSuccess(true);
                     result.setResponse(obj);

+ 3 - 3
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recommend/ArticleCategoryService.java

@@ -11,7 +11,7 @@ import com.tzld.longarticle.recommend.server.mapper.aigc.AigcBaseMapper;
 import com.tzld.longarticle.recommend.server.mapper.longArticle.ArticleCategoryMapper;
 import com.tzld.longarticle.recommend.server.model.dto.CrawlerContent;
 import com.tzld.longarticle.recommend.server.model.dto.ProduceContentDTO;
-import com.tzld.longarticle.recommend.server.model.dto.kimi.KimiResult;
+import com.tzld.longarticle.recommend.server.model.dto.kimi.AIResult;
 import com.tzld.longarticle.recommend.server.model.entity.aigc.ProducePlan;
 import com.tzld.longarticle.recommend.server.model.entity.aigc.ProducePlanExeRecord;
 import com.tzld.longarticle.recommend.server.model.entity.longArticle.ArticleCategory;
@@ -115,7 +115,7 @@ public class ArticleCategoryService {
         for (List<ArticleCategory> partition : partitionList) {
             List<String> partitionTitles = partition.stream().map(ArticleCategory::getTitle).distinct().collect(Collectors.toList());
             String prompt = buildCategoryPrompt(partitionTitles);
-            KimiResult kimiResult = deepSeekApiService.requestOfficialApi(prompt, null, null, true);
+            AIResult kimiResult = deepSeekApiService.request(prompt, null, null, true);
             long now = System.currentTimeMillis();
             JSONObject obj = null;
             if (kimiResult.isSuccess()) {
@@ -346,7 +346,7 @@ public class ArticleCategoryService {
         for (ArticleCategory articleCategory : dealList) {
             List<String> partitionTitles = Collections.singletonList(articleCategory.getTitle());
             String prompt = buildCategoryPrompt(partitionTitles);
-            KimiResult kimiResult = deepSeekApiService.requestOfficialApi(prompt, null, null, true);
+            AIResult kimiResult = deepSeekApiService.request(prompt, null, null, true);
             long now = System.currentTimeMillis();
             JSONObject obj = null;
             if (kimiResult.isSuccess()) {

+ 2 - 2
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recommend/score/strategy/SimilarityStrategy.java

@@ -1,7 +1,7 @@
 package com.tzld.longarticle.recommend.server.service.recommend.score.strategy;
 
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
-import com.tzld.longarticle.recommend.server.model.dto.kimi.KimiResult;
+import com.tzld.longarticle.recommend.server.model.dto.kimi.AIResult;
 import com.tzld.longarticle.recommend.server.remote.DeepSeekApiService;
 import com.tzld.longarticle.recommend.server.remote.NLPRemoteService;
 import com.tzld.longarticle.recommend.server.repository.crawler.ArticleRepository;
@@ -67,7 +67,7 @@ public class SimilarityStrategy implements ScoreStrategy {
                 if (!StringUtils.hasText(type)) {
                     String prompt = kimiSimilarityTypePrompt.replace("accountName", param.getAccountName());
                     // 调用kimi判断账号类型
-                    KimiResult kimiResult = deepSeekApiService.requestOfficialApi(prompt, null, null, false);
+                    AIResult kimiResult = deepSeekApiService.request(prompt, null, null, false);
                     if (kimiResult.isSuccess()) {
                         try {
                             type = kimiResult.getResponse().getChoices().get(0).getMessage().getContent();

+ 2 - 2
long-article-recommend-service/src/test/java/com/tzld/longarticle/recommend/server/ArticleVideoAuditTest.java

@@ -6,7 +6,7 @@ import com.google.common.collect.Lists;
 import com.tzld.longarticle.recommend.server.common.enums.recommend.ArticleCategoryStatusEnum;
 import com.tzld.longarticle.recommend.server.mapper.longArticle.ArticleAuditMapper;
 import com.tzld.longarticle.recommend.server.mapper.longArticle.ArticleCategoryMapper;
-import com.tzld.longarticle.recommend.server.model.dto.kimi.KimiResult;
+import com.tzld.longarticle.recommend.server.model.dto.kimi.AIResult;
 import com.tzld.longarticle.recommend.server.model.entity.aigc.ProducePlan;
 import com.tzld.longarticle.recommend.server.model.entity.aigc.ProducePlanExeRecord;
 import com.tzld.longarticle.recommend.server.model.entity.longArticle.ArticleCategory;
@@ -94,7 +94,7 @@ public class ArticleVideoAuditTest {
         for (List<ArticleCategory> partition : partitionList) {
             List<String> partitionTitles = partition.stream().map(ArticleCategory::getTitle).distinct().collect(Collectors.toList());
             String prompt = buildKimiPrompt(partitionTitles);
-            KimiResult kimiResult = deepSeekApiService.requestOfficialApi(prompt, null, null, true);
+            AIResult kimiResult = deepSeekApiService.request(prompt, null, null, true);
             long now = System.currentTimeMillis();
             JSONObject obj = null;
             if (kimiResult.isSuccess()) {