diff --git a/core/pom.xml b/core/pom.xml
index e2394e782..23aa645a7 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -471,6 +471,7 @@
**/H2Test.java
**/OshiTest.java
**/CompressTest.java
+ **/com/tlcsdm/core/ai/*.java
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionChoice.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionChoice.java
new file mode 100644
index 000000000..cc0707b23
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionChoice.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatCompletionChoice {
+
+ private int index;
+ private ChatMessage message;
+ private String finishReason;
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public ChatMessage getMessage() {
+ return message;
+ }
+
+ public void setMessage(ChatMessage message) {
+ this.message = message;
+ }
+
+ public String getFinishReason() {
+ return finishReason;
+ }
+
+ public void setFinishReason(String finishReason) {
+ this.finishReason = finishReason;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionDelta.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionDelta.java
new file mode 100644
index 000000000..37b65ffe2
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionDelta.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatCompletionDelta {
+
+ private String content;
+ private String role;
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionRequest.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionRequest.java
new file mode 100644
index 000000000..b46853cbf
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionRequest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+import java.util.List;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatCompletionRequest {
+
+ private String model;
+ private List messages;
+ private Double temperature;
+ private Integer maxTokens;
+ private Boolean stream;
+ private Boolean webSearch;
+ private Boolean deepThought;
+
+ public ChatCompletionRequest() {
+ }
+
+ public ChatCompletionRequest(String model, List messages, Double temperature,
+ Integer maxTokens, Boolean stream, Boolean webSearch, Boolean deepThought) {
+ this.model = model;
+ this.messages = messages;
+ this.temperature = temperature;
+ this.maxTokens = maxTokens;
+ this.stream = stream;
+ this.webSearch = webSearch;
+ this.deepThought = deepThought;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public List getMessages() {
+ return messages;
+ }
+
+ public void setMessages(List messages) {
+ this.messages = messages;
+ }
+
+ public Double getTemperature() {
+ return temperature;
+ }
+
+ public void setTemperature(Double temperature) {
+ this.temperature = temperature;
+ }
+
+ public Integer getMaxTokens() {
+ return maxTokens;
+ }
+
+ public void setMaxTokens(Integer maxTokens) {
+ this.maxTokens = maxTokens;
+ }
+
+ public Boolean getStream() {
+ return stream;
+ }
+
+ public void setStream(Boolean stream) {
+ this.stream = stream;
+ }
+
+ public Boolean getWebSearch() {
+ return webSearch;
+ }
+
+ public void setWebSearch(Boolean webSearch) {
+ this.webSearch = webSearch;
+ }
+
+ public Boolean getDeepThought() {
+ return deepThought;
+ }
+
+ public void setDeepThought(Boolean deepThought) {
+ this.deepThought = deepThought;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionResponse.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionResponse.java
new file mode 100644
index 000000000..46bf83daf
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionResponse.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+import java.util.List;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatCompletionResponse {
+
+ private String id;
+ private String object;
+ private long created;
+ private String model;
+ private List choices;
+ private Usage usage;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getObject() {
+ return object;
+ }
+
+ public void setObject(String object) {
+ this.object = object;
+ }
+
+ public long getCreated() {
+ return created;
+ }
+
+ public void setCreated(long created) {
+ this.created = created;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public List getChoices() {
+ return choices;
+ }
+
+ public void setChoices(List choices) {
+ this.choices = choices;
+ }
+
+ public Usage getUsage() {
+ return usage;
+ }
+
+ public void setUsage(Usage usage) {
+ this.usage = usage;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionStreamChoice.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionStreamChoice.java
new file mode 100644
index 000000000..4ff6819e0
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionStreamChoice.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatCompletionStreamChoice {
+
+ private int index;
+ private ChatCompletionDelta delta;
+ private String finishReason;
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public ChatCompletionDelta getDelta() {
+ return delta;
+ }
+
+ public void setDelta(ChatCompletionDelta delta) {
+ this.delta = delta;
+ }
+
+ public String getFinishReason() {
+ return finishReason;
+ }
+
+ public void setFinishReason(String finishReason) {
+ this.finishReason = finishReason;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionStreamResponse.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionStreamResponse.java
new file mode 100644
index 000000000..d3f74f3df
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatCompletionStreamResponse.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+import java.util.List;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatCompletionStreamResponse {
+
+ private String id;
+ private String object;
+ private long created;
+ private String model;
+ private List choices;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getObject() {
+ return object;
+ }
+
+ public void setObject(String object) {
+ this.object = object;
+ }
+
+ public long getCreated() {
+ return created;
+ }
+
+ public void setCreated(long created) {
+ this.created = created;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public List getChoices() {
+ return choices;
+ }
+
+ public void setChoices(List choices) {
+ this.choices = choices;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatMessage.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatMessage.java
new file mode 100644
index 000000000..68a6c575b
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/ChatMessage.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class ChatMessage {
+
+ private String role;
+ private String content;
+
+ public ChatMessage() {
+ }
+
+ public ChatMessage(String role, String content) {
+ this.role = role;
+ this.content = content;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/DeepSeekApiException.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/DeepSeekApiException.java
new file mode 100644
index 000000000..580b3f8a7
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/DeepSeekApiException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class DeepSeekApiException extends Exception {
+ public DeepSeekApiException(String message) {
+ super(message);
+ }
+
+ public DeepSeekApiException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/DeepSeekChatClient.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/DeepSeekChatClient.java
new file mode 100644
index 000000000..1a9bff5b3
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/DeepSeekChatClient.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.tlcsdm.core.util.JacksonUtil;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class DeepSeekChatClient {
+ private static final String API_BASE_URL = "https://api.deepseek.com/v1";
+ private final HttpClient httpClient;
+ private final ObjectMapper objectMapper;
+ private final String apiKey;
+ //对话上下文
+ private final List conversationHistory;
+
+ public DeepSeekChatClient(String apiKey) {
+ this.apiKey = apiKey;
+ this.conversationHistory = new ArrayList<>();
+ this.httpClient = HttpClient.newBuilder()
+ .version(HttpClient.Version.HTTP_2)
+ .connectTimeout(Duration.ofSeconds(30))
+ .build();
+
+ this.objectMapper = JacksonUtil.getJsonMapper()
+ .registerModule(new JavaTimeModule())
+ .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ }
+
+ // 同步聊天方法
+ public String chat(String userMessage, boolean webSearch, boolean deepThought) throws DeepSeekApiException {
+ return chat(userMessage, "deepseek-chat", webSearch, deepThought, 0.7, null);
+ }
+
+ public String chat(String userMessage, String model, boolean webSearch, boolean deepThought,
+ Double temperature, Integer maxTokens) throws DeepSeekApiException {
+ // 添加用户消息到历史
+ addUserMessage(userMessage);
+
+ // 构建请求
+ ChatCompletionRequest request = new ChatCompletionRequest(
+ model,
+ new ArrayList<>(conversationHistory),
+ temperature,
+ maxTokens,
+ false, // 非流式
+ webSearch,
+ deepThought
+ );
+
+ try {
+ ChatCompletionResponse response = createChatCompletion(request);
+
+ if (response.getChoices() != null && !response.getChoices().isEmpty()) {
+ String assistantReply = response.getChoices().get(0).getMessage().getContent();
+ // 添加助手回复到历史
+ addAssistantMessage(assistantReply);
+ return assistantReply;
+ }
+ throw new DeepSeekApiException("No response choices available");
+ } catch (DeepSeekApiException e) {
+ // 移除最后一条用户消息,因为对话失败
+ if (!conversationHistory.isEmpty() &&
+ "user".equals(conversationHistory.get(conversationHistory.size() - 1).getRole())) {
+ conversationHistory.remove(conversationHistory.size() - 1);
+ }
+ throw e;
+ }
+ }
+
+ // 异步流式聊天方法
+ public CompletableFuture chatStream(String userMessage, boolean webSearch, boolean deepThought,
+ Consumer chunkConsumer) {
+ return chatStream(userMessage, "deepseek-chat", webSearch, deepThought, 0.7, null, chunkConsumer);
+ }
+
+ public CompletableFuture chatStream(String userMessage, String model, boolean webSearch, boolean deepThought,
+ Double temperature, Integer maxTokens, Consumer chunkConsumer) {
+ // 添加用户消息到历史
+ addUserMessage(userMessage);
+
+ // 构建请求
+ ChatCompletionRequest request = new ChatCompletionRequest(
+ model,
+ new ArrayList<>(conversationHistory),
+ temperature,
+ maxTokens,
+ true, // 流式
+ webSearch,
+ deepThought
+ );
+
+ CompletableFuture future = new CompletableFuture<>();
+ StringBuilder fullResponse = new StringBuilder();
+
+ try {
+ String requestBody = objectMapper.writeValueAsString(request);
+
+ HttpRequest httpRequest = HttpRequest.newBuilder()
+ .uri(URI.create(API_BASE_URL + "/chat/completions"))
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + apiKey)
+ .POST(HttpRequest.BodyPublishers.ofString(requestBody))
+ .build();
+
+ // 使用 sendAsync 并手动处理流
+ httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines())
+ .thenAccept(response -> {
+ if (response.statusCode() >= 200 && response.statusCode() < 300) {
+ try {
+ // 直接处理 Stream
+ response.body().forEach(line -> {
+ try {
+ if (line.startsWith("data: ") && !line.equals("data: [DONE]")) {
+ String data = line.substring(6);
+ ChatCompletionStreamResponse chunk = objectMapper.readValue(
+ data, ChatCompletionStreamResponse.class);
+
+ if (chunk.getChoices() != null && !chunk.getChoices().isEmpty()) {
+ String content = chunk.getChoices().get(0).getDelta().getContent();
+ if (content != null) {
+ chunkConsumer.accept(content);
+ fullResponse.append(content);
+ }
+ }
+ }
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ }
+ });
+
+ // 添加助手回复到历史
+ String responseText = fullResponse.toString();
+ addAssistantMessage(responseText);
+ future.complete(responseText);
+
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ } finally {
+ response.body().close();
+ }
+ } else {
+ future.completeExceptionally(new DeepSeekApiException(
+ "API request failed with status code: " + response.statusCode()));
+ }
+ })
+ .exceptionally(e -> {
+ future.completeExceptionally(e);
+ return null;
+ });
+
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ }
+
+ return future;
+ }
+
+ // 历史记录管理方法
+ public void addSystemMessage(String content) {
+ conversationHistory.add(new ChatMessage("system", content));
+ }
+
+ public void addUserMessage(String content) {
+ conversationHistory.add(new ChatMessage("user", content));
+ }
+
+ public void addAssistantMessage(String content) {
+ conversationHistory.add(new ChatMessage("assistant", content));
+ }
+
+ public void clearConversationHistory() {
+ conversationHistory.clear();
+ }
+
+ public List getConversationHistory() {
+ return new ArrayList<>(conversationHistory);
+ }
+
+ // 核心API调用方法
+ private ChatCompletionResponse createChatCompletion(ChatCompletionRequest request) throws DeepSeekApiException {
+ try {
+ String requestBody = objectMapper.writeValueAsString(request);
+
+ HttpRequest httpRequest = HttpRequest.newBuilder()
+ .uri(URI.create(API_BASE_URL + "/chat/completions"))
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + apiKey)
+ .POST(HttpRequest.BodyPublishers.ofString(requestBody))
+ .build();
+
+ HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() >= 200 && response.statusCode() < 300) {
+ return objectMapper.readValue(response.body(), ChatCompletionResponse.class);
+ } else {
+ throw new DeepSeekApiException("API request failed with status code: " + response.statusCode() +
+ ", response: " + response.body());
+ }
+ } catch (JsonProcessingException e) {
+ throw new DeepSeekApiException("Failed to serialize request or deserialize response", e);
+ } catch (Exception e) {
+ throw new DeepSeekApiException("HTTP request failed", e);
+ }
+ }
+}
diff --git a/core/src/main/java/com/tlcsdm/core/ai/deepseek/Usage.java b/core/src/main/java/com/tlcsdm/core/ai/deepseek/Usage.java
new file mode 100644
index 000000000..e1e37f49a
--- /dev/null
+++ b/core/src/main/java/com/tlcsdm/core/ai/deepseek/Usage.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai.deepseek;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+public class Usage {
+ private int promptTokens;
+ private int completionTokens;
+ private int totalTokens;
+
+ public int getPromptTokens() {
+ return promptTokens;
+ }
+
+ public void setPromptTokens(int promptTokens) {
+ this.promptTokens = promptTokens;
+ }
+
+ public int getCompletionTokens() {
+ return completionTokens;
+ }
+
+ public void setCompletionTokens(int completionTokens) {
+ this.completionTokens = completionTokens;
+ }
+
+ public int getTotalTokens() {
+ return totalTokens;
+ }
+
+ public void setTotalTokens(int totalTokens) {
+ this.totalTokens = totalTokens;
+ }
+}
diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java
index 71544fff1..f61d726df 100644
--- a/core/src/main/java/module-info.java
+++ b/core/src/main/java/module-info.java
@@ -49,6 +49,8 @@
requires static com.fasterxml.jackson.core;
requires static com.fasterxml.jackson.databind;
requires static com.fasterxml.jackson.annotation;
+ requires static com.fasterxml.jackson.dataformat.yaml;
+ requires static com.fasterxml.jackson.datatype.jsr310;
requires static org.dom4j;
requires static org.apache.commons.jexl3;
requires static org.apache.groovy;
@@ -73,8 +75,6 @@
requires static com.sun.jna.platform;
requires static vosk;
requires static jakarta.xml.bind;
- requires static com.fasterxml.jackson.dataformat.yaml;
- requires static com.fasterxml.jackson.datatype.jsr310;
requires static org.python.jython2;
requires static com.zaxxer.hikari;
requires static druid;
@@ -131,6 +131,8 @@
exports com.tlcsdm.core.database;
exports com.tlcsdm.core.oshi;
exports com.tlcsdm.core.powershell;
+ exports com.tlcsdm.core.watermark;
+ exports com.tlcsdm.core.ai.deepseek;
uses com.tlcsdm.core.freemarker.TemplateLoaderService;
uses com.tlcsdm.core.groovy.GroovyLoaderService;
diff --git a/core/src/test/java/com/tlcsdm/core/ai/DeepseekTest.java b/core/src/test/java/com/tlcsdm/core/ai/DeepseekTest.java
new file mode 100644
index 000000000..212ebd2cb
--- /dev/null
+++ b/core/src/test/java/com/tlcsdm/core/ai/DeepseekTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2025 unknowIfGuestInDream.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of unknowIfGuestInDream, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL UNKNOWIFGUESTINDREAM BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.tlcsdm.core.ai;
+
+import cn.hutool.crypto.Mode;
+import cn.hutool.crypto.Padding;
+import cn.hutool.crypto.symmetric.AES;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.tlcsdm.core.ai.deepseek.DeepSeekApiException;
+import com.tlcsdm.core.ai.deepseek.DeepSeekChatClient;
+import com.tlcsdm.core.util.JacksonUtil;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author unknowIfGuestInDream
+ */
+class DeepseekTest {
+
+ private static final String aesKey = "3f4alpd3525678154a5e3a0183d8087b";
+ private static final String encryptStr = "aac70872f21545ff2c56a590188bbe4c20035e0e130568c8dabeb699947e6cdf6df2dd72f573c55a8829ea53a2e22cd4";
+ private static String token;
+
+ @BeforeAll
+ static void init() {
+ AES aes = new AES(Mode.ECB, Padding.PKCS5Padding, aesKey.getBytes());
+ token = aes.decryptStr(encryptStr);
+ }
+
+ @Test
+ void ds() throws DeepSeekApiException {
+ String apiKey = token;
+ DeepSeekChatClient client = new DeepSeekChatClient(apiKey);
+ // 简单对话
+ System.out.println("用户: 你好,你是谁?");
+ String reply = client.chat("你好,你是谁?", false, true);
+ System.out.println("助手: " + reply);
+
+ // 带上下文的后续对话
+ System.out.println("用户: 我刚才问了你什么?");
+ reply = client.chat("我刚才问了你什么?", false, false);
+ System.out.println("助手: " + reply);
+
+ // 流式对话
+ System.out.println("用户: 请用流式方式告诉我关于Java 17的新特性");
+ client.chatStream("请用流式方式告诉我关于Java 17的新特性", true, false, chunk -> {
+ System.out.print(chunk);
+ System.out.flush();
+ }).join();
+
+ // 查看对话历史
+ System.out.println("\n对话历史:");
+ client.getConversationHistory().forEach(msg -> {
+ System.out.println(msg.getRole() + ": " + msg.getContent());
+ });
+ }
+
+ @Test
+ void use() throws DeepSeekApiException {
+ String apiKey = token;
+ DeepSeekChatClient client = new DeepSeekChatClient(apiKey);
+
+ // 1. 简单对话
+ String response = client.chat("Java 17有什么新特性?", true, false);
+ System.out.println(response);
+
+ // 2. 流式对话
+ client.chatStream("详细解释Java 17的密封类", true, true, chunk -> {
+ System.out.print(chunk);
+ }).join();
+
+ // 3. 带上下文的对话
+ client.addUserMessage("记住我的名字是张三");
+ client.addUserMessage("我的名字是什么?");
+ String reply = client.chat("", false, false); // 空消息会使用历史上下文
+ System.out.println(reply); // 应该回答"张三"
+ }
+
+ /**
+ * 高级功能配置.
+ */
+ @Test
+ void useBuilder() throws DeepSeekApiException {
+ String apiKey = token;
+ DeepSeekChatClient client = new DeepSeekChatClient(apiKey);
+ // 使用特定模型,设置温度和最大token数
+ String reply = client.chat("你的知识截止到什么时候?",
+ "deepseek-chat", // 模型
+ false, // 不使用联网搜索
+ true, // 启用深度思考
+ 0.5, // 温度参数
+ 500); // 最大token数
+ System.out.println(reply);
+
+ // 在对话开始前设置系统角色消息
+ client.addSystemMessage("你是一个专业的Java开发助手,回答要简洁专业");
+
+ // 自定义流式响应处理器
+ CompletableFuture future = client.chatStream(
+ "解释JVM的工作原理",
+ "deepseek-chat",
+ false,
+ true,
+ 0.7,
+ null,
+ chunk -> {
+ // 实时打印流式响应
+ System.out.print(chunk);
+ System.out.flush();
+ });
+
+ //为流式响应添加超时机制
+ // future.orTimeout(30, TimeUnit.SECONDS)
+ // .exceptionally(e -> {
+ // if (e instanceof TimeoutException) {
+ // System.err.println("响应超时");
+ // }
+ // return null;
+ // });
+
+ future.thenAccept(fullResponse -> {
+ System.out.println("\n\n完整响应已接收,长度: " + fullResponse.length());
+ }).exceptionally(e -> {
+ System.err.println("对话失败: " + e.getMessage());
+ return null;
+ }).join();
+ }
+
+ /**
+ * 查询账户余额.
+ */
+ @Test
+ void queryUsage() throws Exception {
+ String endpoint = "/user/balance";
+ JsonNode response = makeApiRequest(endpoint, "GET", null);
+
+ System.out.println("\n账户余额信息:");
+ System.out.println("当前账户是否有余额可供 API 调用: " + response.path("is_available").asBoolean());
+ response.path("balance_infos").valueStream().forEach(e -> {
+ System.out.println("货币: " + e.path("currency").asText());
+ System.out.println("总的可用余额: " + e.path("total_balance").asText());
+ System.out.println("未过期的赠金余额: " + e.path("granted_balance").asText());
+ System.out.println("充值余额: " + e.path("topped_up_balance").asText());
+ });
+ }
+
+ /**
+ * 列出可用模型.
+ */
+ @Test
+ void listModels() throws Exception {
+ String endpoint = "/models";
+ JsonNode response = makeApiRequest(endpoint, "GET", null);
+
+ System.out.println("\n可用模型列表:");
+ JsonNode models = response.path("data");
+ for (JsonNode model : models) {
+ System.out.println("\n模型ID: " + model.path("id").asText());
+ System.out.println("组织: " + model.path("owned_by").asText());
+ }
+ }
+
+ /**
+ * 通用的API请求方法.
+ */
+ private static JsonNode makeApiRequest(String endpoint, String method, String requestBody) throws Exception {
+ HttpClient httpClient = HttpClient.newBuilder()
+ .version(HttpClient.Version.HTTP_2)
+ .connectTimeout(Duration.ofSeconds(10))
+ .build();
+ HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
+ .uri(URI.create("https://api.deepseek.com/v1" + endpoint))
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + token);
+
+ if ("GET".equalsIgnoreCase(method)) {
+ requestBuilder.GET();
+ } else if ("POST".equalsIgnoreCase(method)) {
+ requestBuilder.POST(HttpRequest.BodyPublishers.ofString(requestBody));
+ } else {
+ throw new IllegalArgumentException("不支持的HTTP方法: " + method);
+ }
+
+ HttpRequest request = requestBuilder.build();
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("API请求失败: " + response.statusCode() + " - " + response.body());
+ }
+ ObjectMapper objectMapper = JacksonUtil.getJsonMapper();
+ return objectMapper.readTree(response.body());
+ }
+}