Skip to content

Commit c54dfd3

Browse files
mxsl-grmarkpollack
authored andcommitted
feat: add deepseek starter and docs - fix pom module ordering
- Add remaining deepseek modules - Fix build order to put autoconfig modules after model modules to fix javadoc build Signed-off-by: GR <[email protected]>
1 parent d619e25 commit c54dfd3

File tree

19 files changed

+1497
-160
lines changed

19 files changed

+1497
-160
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.springframework.ai</groupId>
8+
<artifactId>spring-ai-parent</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
<relativePath>../../../pom.xml</relativePath>
11+
</parent>
12+
<artifactId>spring-ai-autoconfigure-model-deepseek</artifactId>
13+
<packaging>jar</packaging>
14+
<name>Spring AI DeepSeek Auto Configuration</name>
15+
<description>Spring AI DeepSeek Auto Configuration</description>
16+
<url>https://github.com/spring-projects/spring-ai</url>
17+
18+
<scm>
19+
<url>https://github.com/spring-projects/spring-ai</url>
20+
<connection>git://github.com/spring-projects/spring-ai.git</connection>
21+
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
22+
</scm>
23+
24+
25+
<dependencies>
26+
27+
<!-- Spring AI dependencies -->
28+
29+
<dependency>
30+
<groupId>org.springframework.ai</groupId>
31+
<artifactId>spring-ai-deepseek</artifactId>
32+
<version>${project.parent.version}</version>
33+
<optional>true</optional>
34+
</dependency>
35+
36+
<!-- Spring AI auto configurations -->
37+
38+
<dependency>
39+
<groupId>org.springframework.ai</groupId>
40+
<artifactId>spring-ai-autoconfigure-model-tool</artifactId>
41+
<version>${project.parent.version}</version>
42+
</dependency>
43+
44+
<dependency>
45+
<groupId>org.springframework.ai</groupId>
46+
<artifactId>spring-ai-autoconfigure-retry</artifactId>
47+
<version>${project.parent.version}</version>
48+
</dependency>
49+
50+
<dependency>
51+
<groupId>org.springframework.ai</groupId>
52+
<artifactId>spring-ai-autoconfigure-model-chat-observation</artifactId>
53+
<version>${project.parent.version}</version>
54+
</dependency>
55+
56+
<!-- Boot dependencies -->
57+
<dependency>
58+
<groupId>org.springframework.boot</groupId>
59+
<artifactId>spring-boot-starter</artifactId>
60+
<optional>true</optional>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.springframework.boot</groupId>
65+
<artifactId>spring-boot-configuration-processor</artifactId>
66+
<optional>true</optional>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.springframework.boot</groupId>
71+
<artifactId>spring-boot-autoconfigure-processor</artifactId>
72+
<optional>true</optional>
73+
</dependency>
74+
75+
<!-- Test dependencies -->
76+
<dependency>
77+
<groupId>org.springframework.ai</groupId>
78+
<artifactId>spring-ai-test</artifactId>
79+
<version>${project.parent.version}</version>
80+
<scope>test</scope>
81+
</dependency>
82+
83+
<dependency>
84+
<groupId>org.springframework.boot</groupId>
85+
<artifactId>spring-boot-starter-test</artifactId>
86+
<scope>test</scope>
87+
</dependency>
88+
89+
<dependency>
90+
<groupId>org.mockito</groupId>
91+
<artifactId>mockito-core</artifactId>
92+
<scope>test</scope>
93+
</dependency>
94+
</dependencies>
95+
96+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.deepseek.autoconfigure;
18+
19+
import io.micrometer.observation.ObservationRegistry;
20+
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
21+
import org.springframework.ai.model.SimpleApiKey;
22+
import org.springframework.ai.deepseek.DeepSeekChatModel;
23+
import org.springframework.ai.deepseek.api.DeepSeekApi;
24+
import org.springframework.ai.model.SpringAIModelProperties;
25+
import org.springframework.ai.model.SpringAIModels;
26+
import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate;
27+
import org.springframework.ai.model.tool.ToolCallingManager;
28+
import org.springframework.ai.model.tool.ToolExecutionEligibilityPredicate;
29+
import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration;
30+
import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration;
31+
import org.springframework.beans.factory.ObjectProvider;
32+
import org.springframework.boot.autoconfigure.AutoConfiguration;
33+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
35+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
36+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
37+
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
38+
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
39+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
40+
import org.springframework.context.annotation.Bean;
41+
import org.springframework.retry.support.RetryTemplate;
42+
import org.springframework.util.Assert;
43+
import org.springframework.util.StringUtils;
44+
import org.springframework.web.client.ResponseErrorHandler;
45+
import org.springframework.web.client.RestClient;
46+
import org.springframework.web.reactive.function.client.WebClient;
47+
48+
/**
49+
* {@link AutoConfiguration Auto-configuration} for DeepSeek Chat Model.
50+
*
51+
* @author Geng Rong
52+
*/
53+
@AutoConfiguration(after = { RestClientAutoConfiguration.class, WebClientAutoConfiguration.class,
54+
SpringAiRetryAutoConfiguration.class, ToolCallingAutoConfiguration.class })
55+
@ConditionalOnClass(DeepSeekApi.class)
56+
@EnableConfigurationProperties({ DeepSeekConnectionProperties.class, DeepSeekChatProperties.class })
57+
@ConditionalOnProperty(name = SpringAIModelProperties.CHAT_MODEL, havingValue = SpringAIModels.DEEPSEEK,
58+
matchIfMissing = true)
59+
@ImportAutoConfiguration(classes = { SpringAiRetryAutoConfiguration.class, RestClientAutoConfiguration.class,
60+
WebClientAutoConfiguration.class, ToolCallingAutoConfiguration.class })
61+
public class DeepSeekChatAutoConfiguration {
62+
63+
@Bean
64+
@ConditionalOnMissingBean
65+
public DeepSeekChatModel deepSeekChatModel(DeepSeekConnectionProperties commonProperties,
66+
DeepSeekChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
67+
ObjectProvider<WebClient.Builder> webClientBuilderProvider, ToolCallingManager toolCallingManager,
68+
RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler,
69+
ObjectProvider<ObservationRegistry> observationRegistry,
70+
ObjectProvider<ChatModelObservationConvention> observationConvention,
71+
ObjectProvider<ToolExecutionEligibilityPredicate> deepseekToolExecutionEligibilityPredicate) {
72+
73+
var deepSeekApi = deepSeekApi(chatProperties, commonProperties,
74+
restClientBuilderProvider.getIfAvailable(RestClient::builder),
75+
webClientBuilderProvider.getIfAvailable(WebClient::builder), responseErrorHandler);
76+
77+
var chatModel = DeepSeekChatModel.builder()
78+
.deepSeekApi(deepSeekApi)
79+
.defaultOptions(chatProperties.getOptions())
80+
.toolCallingManager(toolCallingManager)
81+
.toolExecutionEligibilityPredicate(deepseekToolExecutionEligibilityPredicate
82+
.getIfUnique(DefaultToolExecutionEligibilityPredicate::new))
83+
.retryTemplate(retryTemplate)
84+
.observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))
85+
.build();
86+
87+
observationConvention.ifAvailable(chatModel::setObservationConvention);
88+
89+
return chatModel;
90+
}
91+
92+
private DeepSeekApi deepSeekApi(DeepSeekChatProperties chatProperties,
93+
DeepSeekConnectionProperties commonProperties, RestClient.Builder restClientBuilder,
94+
WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) {
95+
96+
String resolvedBaseUrl = StringUtils.hasText(chatProperties.getBaseUrl()) ? chatProperties.getBaseUrl()
97+
: commonProperties.getBaseUrl();
98+
Assert.hasText(resolvedBaseUrl, "DeepSeek base URL must be set");
99+
100+
String resolvedApiKey = StringUtils.hasText(chatProperties.getApiKey()) ? chatProperties.getApiKey()
101+
: commonProperties.getApiKey();
102+
Assert.hasText(resolvedApiKey, "DeepSeek API key must be set");
103+
104+
return DeepSeekApi.builder()
105+
.baseUrl(resolvedBaseUrl)
106+
.apiKey(new SimpleApiKey(resolvedApiKey))
107+
.completionsPath(chatProperties.getCompletionsPath())
108+
.betaPrefixPath(chatProperties.getBetaPrefixPath())
109+
.restClientBuilder(restClientBuilder)
110+
.webClientBuilder(webClientBuilder)
111+
.responseErrorHandler(responseErrorHandler)
112+
.build();
113+
}
114+
115+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.deepseek.autoconfigure;
18+
19+
import org.springframework.ai.deepseek.DeepSeekChatOptions;
20+
import org.springframework.ai.deepseek.api.DeepSeekApi;
21+
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
import org.springframework.boot.context.properties.NestedConfigurationProperty;
23+
24+
/**
25+
* Configuration properties for DeepSeek chat client.
26+
*
27+
* @author Geng Rong
28+
*/
29+
@ConfigurationProperties(DeepSeekChatProperties.CONFIG_PREFIX)
30+
public class DeepSeekChatProperties extends DeepSeekParentProperties {
31+
32+
public static final String CONFIG_PREFIX = "spring.ai.deepseek.chat";
33+
34+
public static final String DEFAULT_CHAT_MODEL = DeepSeekApi.ChatModel.DEEPSEEK_CHAT.getValue();
35+
36+
private static final Double DEFAULT_TEMPERATURE = 1D;
37+
38+
public static final String DEFAULT_COMPLETIONS_PATH = "/chat/completions";
39+
40+
public static final String DEFAULT_BETA_PREFIX_PATH = "/beta";
41+
42+
/**
43+
* Enable DeepSeek chat client.
44+
*/
45+
private boolean enabled = true;
46+
47+
private String completionsPath = DEFAULT_COMPLETIONS_PATH;
48+
49+
private String betaPrefixPath = DEFAULT_BETA_PREFIX_PATH;
50+
51+
@NestedConfigurationProperty
52+
private DeepSeekChatOptions options = DeepSeekChatOptions.builder()
53+
.model(DEFAULT_CHAT_MODEL)
54+
.temperature(DEFAULT_TEMPERATURE)
55+
.build();
56+
57+
public DeepSeekChatOptions getOptions() {
58+
return this.options;
59+
}
60+
61+
public void setOptions(DeepSeekChatOptions options) {
62+
this.options = options;
63+
}
64+
65+
public boolean isEnabled() {
66+
return this.enabled;
67+
}
68+
69+
public void setEnabled(boolean enabled) {
70+
this.enabled = enabled;
71+
}
72+
73+
public String getCompletionsPath() {
74+
return completionsPath;
75+
}
76+
77+
public void setCompletionsPath(String completionsPath) {
78+
this.completionsPath = completionsPath;
79+
}
80+
81+
public String getBetaPrefixPath() {
82+
return betaPrefixPath;
83+
}
84+
85+
public void setBetaPrefixPath(String betaPrefixPath) {
86+
this.betaPrefixPath = betaPrefixPath;
87+
}
88+
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.deepseek.autoconfigure;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Parent properties for DeepSeek.
23+
*
24+
* @author Geng Rong
25+
*/
26+
@ConfigurationProperties(DeepSeekConnectionProperties.CONFIG_PREFIX)
27+
public class DeepSeekConnectionProperties extends DeepSeekParentProperties {
28+
29+
public static final String CONFIG_PREFIX = "spring.ai.deepseek";
30+
31+
public static final String DEFAULT_BASE_URL = "https://api.deepseek.com";
32+
33+
public DeepSeekConnectionProperties() {
34+
super.setBaseUrl(DEFAULT_BASE_URL);
35+
}
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.deepseek.autoconfigure;
18+
19+
/**
20+
* Parent properties for DeepSeek.
21+
*
22+
* @author Geng Rong
23+
*/
24+
public class DeepSeekParentProperties {
25+
26+
private String apiKey;
27+
28+
private String baseUrl;
29+
30+
public String getApiKey() {
31+
return this.apiKey;
32+
}
33+
34+
public void setApiKey(String apiKey) {
35+
this.apiKey = apiKey;
36+
}
37+
38+
public String getBaseUrl() {
39+
return this.baseUrl;
40+
}
41+
42+
public void setBaseUrl(String baseUrl) {
43+
this.baseUrl = baseUrl;
44+
}
45+
46+
}

0 commit comments

Comments
 (0)