Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2025-2025 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-autoconfigure-model-replicate</artifactId>
<packaging>jar</packaging>
<name>Spring AI Replicate Auto Configuration</name>
<description>Spring AI Replicate Auto Configuration</description>
<url>https://github.com/spring-projects/spring-ai</url>

<scm>
<url>https://github.com/spring-projects/spring-ai</url>
<connection>git://github.com/spring-projects/spring-ai.git</connection>
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
</scm>

<dependencies>

<!-- Spring AI dependencies -->

<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-replicate</artifactId>
<version>${project.parent.version}</version>
</dependency>

<!-- Spring AI auto configurations -->

<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-retry</artifactId>
<version>${project.parent.version}</version>
</dependency>

<!-- Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-test</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2025-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.ai.model.replicate.autoconfigure;

import io.micrometer.observation.ObservationRegistry;

import org.springframework.ai.replicate.ReplicateChatModel;
import org.springframework.ai.replicate.ReplicateMediaModel;
import org.springframework.ai.replicate.ReplicateStringModel;
import org.springframework.ai.replicate.ReplicateStructuredModel;
import org.springframework.ai.replicate.api.ReplicateApi;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;

/**
* {@link AutoConfiguration Auto-configuration} for Replicate models.
*
* @author Rene Maierhofer
* @since 1.1.0
*/
@AutoConfiguration(after = RestClientAutoConfiguration.class)
@ConditionalOnClass(ReplicateApi.class)
@EnableConfigurationProperties({ ReplicateConnectionProperties.class, ReplicateChatProperties.class,
ReplicateMediaProperties.class, ReplicateStringProperties.class, ReplicateStructuredProperties.class })
@ConditionalOnProperty(prefix = ReplicateConnectionProperties.CONFIG_PREFIX, name = "api-token")
public class ReplicateChatAutoConfiguration {

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = ReplicateConnectionProperties.CONFIG_PREFIX, name = "api-token")
public ReplicateApi replicateApi(ReplicateConnectionProperties connectionProperties,
ObjectProvider<RestClient.Builder> restClientBuilderProvider,
ObjectProvider<ResponseErrorHandler> responseErrorHandlerProvider) {

if (!StringUtils.hasText(connectionProperties.getApiToken())) {
throw new IllegalArgumentException(
"Replicate API token must be configured via spring.ai.replicate.api-token");
}

var builder = ReplicateApi.builder()
.apiKey(connectionProperties.getApiToken())
.baseUrl(connectionProperties.getBaseUrl());

RestClient.Builder restClientBuilder = restClientBuilderProvider.getIfAvailable(RestClient::builder);
if (restClientBuilder != null) {
builder.restClientBuilder(restClientBuilder);
}

ResponseErrorHandler errorHandler = responseErrorHandlerProvider.getIfAvailable();
if (errorHandler != null) {
builder.responseErrorHandler(errorHandler);
}

return builder.build();
}

@Bean
@ConditionalOnMissingBean
public ReplicateChatModel replicateChatModel(ReplicateApi replicateApi, ReplicateChatProperties chatProperties,
ObjectProvider<ObservationRegistry> observationRegistry) {
return ReplicateChatModel.builder()
.replicateApi(replicateApi)
.observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))
.defaultOptions(chatProperties.getOptions())
.build();
}

@Bean
@ConditionalOnMissingBean
public ReplicateMediaModel replicateMediaModel(ReplicateApi replicateApi,
ReplicateMediaProperties mediaProperties) {
return ReplicateMediaModel.builder()
.replicateApi(replicateApi)
.defaultOptions(mediaProperties.getOptions())
.build();
}

@Bean
@ConditionalOnMissingBean
public ReplicateStringModel replicateStringModel(ReplicateApi replicateApi,
ReplicateStringProperties stringProperties) {
return ReplicateStringModel.builder()
.replicateApi(replicateApi)
.defaultOptions(stringProperties.getOptions())
.build();
}

@Bean
@ConditionalOnMissingBean
public ReplicateStructuredModel replicateStructuredModel(ReplicateApi replicateApi,
ReplicateStructuredProperties structuredProperties) {

return ReplicateStructuredModel.builder()
.replicateApi(replicateApi)
.defaultOptions(structuredProperties.getOptions())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2025-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.ai.model.replicate.autoconfigure;

import org.springframework.ai.replicate.ReplicateChatOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

/**
* Chat properties for Replicate AI.
*
* @author Rene Maierhofer
* @since 1.1.0
*/
@ConfigurationProperties(ReplicateChatProperties.CONFIG_PREFIX)
public class ReplicateChatProperties {

public static final String CONFIG_PREFIX = "spring.ai.replicate.chat";

@NestedConfigurationProperty
private ReplicateChatOptions options = ReplicateChatOptions.builder().build();

public ReplicateChatOptions getOptions() {
return this.options;
}

public void setOptions(ReplicateChatOptions options) {
this.options = options;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2025-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.ai.model.replicate.autoconfigure;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* Connection properties for Replicate AI.
*
* @author Rene Maierhofer
* @since 1.1.0
*/
@ConfigurationProperties(ReplicateConnectionProperties.CONFIG_PREFIX)
public class ReplicateConnectionProperties {

public static final String CONFIG_PREFIX = "spring.ai.replicate";

public static final String DEFAULT_BASE_URL = "https://api.replicate.com/v1";

private String apiToken;

private String baseUrl = DEFAULT_BASE_URL;

public String getApiToken() {
return this.apiToken;
}

public void setApiToken(String apiToken) {
this.apiToken = apiToken;
}

public String getBaseUrl() {
return this.baseUrl;
}

public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2025-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.ai.model.replicate.autoconfigure;

import org.springframework.ai.replicate.ReplicateOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

/**
* Media model properties for Replicate AI. Used for image, video, and audio generation
* models.
*
* @author Rene Maierhofer
* @since 1.1.0
*/
@ConfigurationProperties(ReplicateMediaProperties.CONFIG_PREFIX)
public class ReplicateMediaProperties {

public static final String CONFIG_PREFIX = "spring.ai.replicate.media";

@NestedConfigurationProperty
private ReplicateOptions options = ReplicateOptions.builder().build();

public ReplicateOptions getOptions() {
return this.options;
}

public void setOptions(ReplicateOptions options) {
this.options = options;
}

}
Loading