Skip to content

Commit c628b01

Browse files
authored
feat: Upgrade Spring AI to 1.1.0. Upgrade Spring AI Alibaba to 1.1.0.0-M5. (#402)
feat: Upgrade Spring AI to 1.1.0. Upgrade Spring AI Alibaba to 1.1.0.0-M5.
1 parent c66ffde commit c628b01

50 files changed

Lines changed: 203 additions & 802 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pom.xml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@
4141
<maven.compiler.target>17</maven.compiler.target>
4242

4343
<!-- Spring AI -->
44-
<spring-ai.version>1.1.0-M4</spring-ai.version>
44+
<spring-ai.version>1.1.0</spring-ai.version>
45+
<!-- Spring Boot -->
46+
<spring-boot.version>3.5.7</spring-boot.version>
4547

4648
<!-- Spring AI Alibaba -->
4749
<!-- Install Spring AI Alibaba in your local. -->
48-
<spring-ai-alibaba.version>1.1.0.0-M4</spring-ai-alibaba.version>
49-
<spring-ai-extensions.version>1.1.0.0-M4</spring-ai-extensions.version>
50-
<!-- Spring Boot -->
51-
<spring-boot.version>3.4.0</spring-boot.version>
50+
<spring-ai-alibaba.version>1.1.0.0-M5</spring-ai-alibaba.version>
51+
<spring-ai-alibaba.extensions.version>1.1.0.0-M5</spring-ai-alibaba.extensions.version>
5252

5353
<!-- maven plugin -->
5454
<maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>
@@ -109,11 +109,10 @@
109109
<dependency>
110110
<groupId>com.alibaba.cloud.ai</groupId>
111111
<artifactId>spring-ai-alibaba-extensions-bom</artifactId>
112-
<version>${spring-ai-extensions.version}</version>
112+
<version>${spring-ai-alibaba.extensions.version}</version>
113113
<type>pom</type>
114114
<scope>import</scope>
115115
</dependency>
116-
117116
</dependencies>
118117
</dependencyManagement>
119118

spring-ai-alibaba-agent-example/playground-flight-booking/src/main/java/ai/spring/demo/ai/playground/services/CustomerSupportAssistant.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public CustomerSupportAssistant(ChatClient.Builder modelBuilder, VectorStore vec
6767
PromptChatMemoryAdvisor.builder(chatMemory).build(), // Chat Memory
6868
// new VectorStoreChatMemoryAdvisor(vectorStore)),
6969

70-
new QuestionAnswerAdvisor(vectorStore), // RAG
70+
QuestionAnswerAdvisor.builder(vectorStore).build(), // RAG
7171
// new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()
7272
// .withFilterExpression("'documentType' == 'terms-of-service' && region in ['EU', 'US']")),
7373

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
# Aduio Transcription API
22

3-
### STT(speech to text) API
4-
GET http://127.0.0.1:10009/ai/transcription
3+
### STT(speech to text) call API
4+
GET http://127.0.0.1:10009/ai/transcription/call
55

66
### STT(speech to text) stream API
77
GET http://127.0.0.1:10009/ai/transcription/stream
88

9-
### STT(speech to text) async API
10-
GET http://127.0.0.1:10009/ai/transcription/async
11-
129
# Audio Speech API
1310

1411
### TTS(text to speech) API
15-
GET http://127.0.0.1:10009/ai/speech
12+
GET http://127.0.0.1:10009/ai/speech/call
1613

1714
### TTS(text to speech) stream API
1815
GET http://127.0.0.1:10009/ai/speech/stream

spring-ai-alibaba-audio-example/dashscope-audio/src/main/java/com/alibaba/cloud/ai/example/audio/AudioSpeechController.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import com.alibaba.cloud.ai.dashscope.audio.synthesis.SpeechSynthesisPrompt;
2323
import com.alibaba.cloud.ai.dashscope.audio.synthesis.SpeechSynthesisResponse;
2424
import jakarta.annotation.PreDestroy;
25+
26+
import com.alibaba.cloud.ai.dashscope.spec.DashScopeModel;
2527
import org.apache.commons.io.FileUtils;
2628
import org.springframework.boot.ApplicationArguments;
2729
import org.springframework.boot.ApplicationRunner;
@@ -64,7 +66,7 @@ public void tts() throws IOException {
6466
new SpeechSynthesisPrompt(
6567
TEXT,
6668
DashScopeAudioSpeechOptions.builder()
67-
.model(DashScopeAudioSpeechApi.AudioSpeechModel.SAM_BERT_ZHICHU_V1.getValue())
69+
.model(DashScopeModel.AudioModel.SAMBERT_ZHICHU_V1.getValue())
6870
.build()
6971
)
7072
);
@@ -86,7 +88,7 @@ public void streamTTS() {
8688
new SpeechSynthesisPrompt(
8789
TEXT,
8890
DashScopeAudioSpeechOptions.builder()
89-
.model(DashScopeAudioSpeechApi.AudioSpeechModel.SAM_BERT_ZHITING_V1.getValue())
91+
.model(DashScopeModel.AudioModel.SAMBERT_ZHITING_V1.getValue())
9092
.build()
9193
)
9294
);

spring-ai-alibaba-audio-example/dashscope-audio/src/main/java/com/alibaba/cloud/ai/example/audio/AudioTranscriptionController.java

Lines changed: 26 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,25 @@
1616

1717
package com.alibaba.cloud.ai.example.audio;
1818

19-
import com.alibaba.cloud.ai.dashscope.api.DashScopeAudioTranscriptionApi;
2019
import com.alibaba.cloud.ai.dashscope.audio.DashScopeAudioTranscriptionOptions;
2120
import com.alibaba.cloud.ai.dashscope.audio.transcription.AudioTranscriptionModel;
22-
import com.alibaba.cloud.ai.dashscope.common.DashScopeException;
21+
import com.alibaba.cloud.ai.dashscope.spec.DashScopeModel;
2322
import org.slf4j.Logger;
2423
import org.slf4j.LoggerFactory;
24+
import org.springframework.ai.audio.transcription.AudioTranscription;
2525
import org.springframework.ai.audio.transcription.AudioTranscriptionPrompt;
2626
import org.springframework.ai.audio.transcription.AudioTranscriptionResponse;
27-
import org.springframework.core.io.FileSystemResource;
27+
import org.springframework.core.io.ClassPathResource;
28+
import org.springframework.core.io.DefaultResourceLoader;
29+
import org.springframework.core.io.Resource;
2830
import org.springframework.web.bind.annotation.GetMapping;
2931
import org.springframework.web.bind.annotation.RequestMapping;
3032
import org.springframework.web.bind.annotation.RestController;
3133
import reactor.core.publisher.Flux;
3234

33-
import java.nio.file.Path;
34-
import java.nio.file.Paths;
35-
import java.util.Objects;
36-
import java.util.concurrent.CountDownLatch;
3735
import java.util.concurrent.Executors;
3836
import java.util.concurrent.ScheduledExecutorService;
39-
import java.util.concurrent.TimeUnit;
37+
import java.util.stream.Collectors;
4038

4139
/**
4240
* 语音转文本(语音合成)
@@ -53,7 +51,7 @@ public class AudioTranscriptionController {
5351
private static final Logger log = LoggerFactory.getLogger(AudioTranscriptionController.class);
5452

5553
// 模型列表:https://help.aliyun.com/zh/model-studio/sambert-websocket-api
56-
private static final String DEFAULT_MODEL = DashScopeAudioTranscriptionApi.AudioTranscriptionModel.PARAFORMER_REALTIME_V2.getValue();
54+
private static final String DEFAULT_MODEL = DashScopeModel.AudioModel.PARAFORMER_V2.getValue();
5755

5856
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
5957

@@ -62,15 +60,20 @@ public AudioTranscriptionController(AudioTranscriptionModel transcriptionModel)
6260
this.transcriptionModel = transcriptionModel;
6361
}
6462

65-
@GetMapping
66-
public String stt() {
63+
/**
64+
* 录音文件识别
65+
*/
66+
@GetMapping("/call")
67+
public String callSTT() {
6768

68-
String currentDir = System.getProperty("user.dir");
69-
Path filePath = Paths.get(currentDir, "hello_world_male_16k_16bit_mono.wav");
69+
// 录音文件支持HTTP / HTTPS协议
70+
// 若录音文件存储在阿里云OSS,使用RESTful API方式支持使用以 oss://为前缀的临时 URL
71+
Resource resource = new DefaultResourceLoader()
72+
.getResource("https://dashscope.oss-cn-beijing.aliyuncs.com/samples/audio/paraformer/hello_world_female2.wav");
7073

7174
AudioTranscriptionResponse response = transcriptionModel.call(
7275
new AudioTranscriptionPrompt(
73-
new FileSystemResource(filePath),
76+
resource,
7477
DashScopeAudioTranscriptionOptions.builder()
7578
.withModel(DEFAULT_MODEL)
7679
.build()
@@ -81,104 +84,29 @@ public String stt() {
8184
}
8285

8386
/**
84-
* 以 Audio Speech 的输出作为输入
87+
* 实时语音识别
8588
*/
8689
@GetMapping("/stream")
8790
public String streamSTT() {
8891

89-
String currentDir = System.getProperty("user.dir");
90-
Path filePath = Paths.get(currentDir, "spring-ai-alibaba-audio-example/dashscope-audio/src/main/resources/gen/tts/output.mp3");
91-
92-
CountDownLatch latch = new CountDownLatch(1);
93-
StringBuilder stringBuilder = new StringBuilder();
94-
92+
ClassPathResource audioResource = new ClassPathResource("hello_world_male_16k_16bit_mono.wav");
9593
Flux<AudioTranscriptionResponse> response = transcriptionModel
9694
.stream(
9795
new AudioTranscriptionPrompt(
98-
new FileSystemResource(filePath),
96+
audioResource,
9997
DashScopeAudioTranscriptionOptions.builder()
100-
.withModel(DEFAULT_MODEL)
98+
.withModel("paraformer-realtime-v2")
10199
.withSampleRate(16000)
102-
.withFormat(DashScopeAudioTranscriptionOptions.AudioFormat.PCM)
100+
.withFormat(DashScopeAudioTranscriptionOptions.AudioFormat.WAV)
103101
.withDisfluencyRemovalEnabled(false)
104102
.build()
105103
)
106104
);
107105

108-
response.doFinally(
109-
signal -> latch.countDown()
110-
).subscribe(
111-
resp -> stringBuilder.append(resp.getResult().getOutput())
112-
);
113-
114-
try {
115-
latch.await();
116-
}
117-
catch (InterruptedException e) {
118-
throw new RuntimeException(e);
119-
}
120-
121-
return stringBuilder.toString();
122-
}
123-
124-
@GetMapping("/async")
125-
public String asyncSTT() {
126-
StringBuilder stringBuilder = new StringBuilder();
127-
CountDownLatch latch = new CountDownLatch(1);
128-
129-
String currentDir = System.getProperty("user.dir");
130-
Path filePath = Paths.get(currentDir, "spring-ai-alibaba-audio-example/dashscope-audio/src/main/resources/gen/tts/output-stream.mp3");
131-
132-
try {
133-
AudioTranscriptionResponse submitResponse = transcriptionModel.asyncCall(
134-
new AudioTranscriptionPrompt(
135-
new FileSystemResource(filePath),
136-
DashScopeAudioTranscriptionOptions.builder()
137-
.withModel(DEFAULT_MODEL)
138-
.build()
139-
)
140-
);
141-
142-
DashScopeAudioTranscriptionApi.Response.Output submitOutput = Objects.requireNonNull(submitResponse.getMetadata()
143-
.get("output"));
144-
String taskId = submitOutput.taskId();
145-
146-
scheduler.scheduleAtFixedRate(
147-
() -> checkTaskStatus(taskId, stringBuilder, latch), 0, 1, TimeUnit.SECONDS);
148-
latch.await();
149-
150-
} catch (InterruptedException e) {
151-
Thread.currentThread().interrupt();
152-
throw new DashScopeException("Thread was interrupted: " + e.getMessage());
153-
}
154-
finally {
155-
scheduler.shutdown();
156-
}
157-
158-
return stringBuilder.toString();
159-
}
160-
161-
private void checkTaskStatus(String taskId, StringBuilder stringBuilder, CountDownLatch latch) {
162-
163-
try {
164-
AudioTranscriptionResponse fetchResponse = transcriptionModel.fetch(taskId);
165-
DashScopeAudioTranscriptionApi.Response.Output fetchOutput =
166-
Objects.requireNonNull(fetchResponse.getMetadata().get("output"));
167-
DashScopeAudioTranscriptionApi.TaskStatus taskStatus = fetchOutput.taskStatus();
168-
169-
if (taskStatus.equals(DashScopeAudioTranscriptionApi.TaskStatus.SUCCEEDED)) {
170-
stringBuilder.append(fetchResponse.getResult().getOutput());
171-
latch.countDown();
172-
}
173-
else if (taskStatus.equals(DashScopeAudioTranscriptionApi.TaskStatus.FAILED)) {
174-
log.warn("Transcription failed.");
175-
latch.countDown();
176-
}
177-
}
178-
catch (Exception e) {
179-
latch.countDown();
180-
throw new RuntimeException("Error occurred while checking task status: " + e.getMessage());
181-
}
106+
return response.map(AudioTranscriptionResponse::getResult)
107+
.map(AudioTranscription::getOutput)
108+
.collect(Collectors.joining())
109+
.block();
182110
}
183111

184112
}

spring-ai-alibaba-chat-example/ollama-chat/src/main/java/com/alibaba/cloud/ai/example/chat/ollama/controller/OllamaChatClientController.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
package com.alibaba.cloud.ai.example.chat.ollama.controller;
1818

1919
import jakarta.servlet.http.HttpServletResponse;
20+
21+
import org.springframework.ai.ollama.api.OllamaChatOptions;
2022
import reactor.core.publisher.Flux;
2123

2224
import org.springframework.ai.chat.client.ChatClient;
2325
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
2426
import org.springframework.ai.chat.model.ChatModel;
25-
import org.springframework.ai.ollama.api.OllamaOptions;
2627
import org.springframework.web.bind.annotation.GetMapping;
2728
import org.springframework.web.bind.annotation.RequestMapping;
2829
import org.springframework.web.bind.annotation.RestController;
@@ -51,7 +52,7 @@ public OllamaChatClientController(ChatModel chatModel) {
5152
)
5253
// 设置 ChatClient 中 ChatModel 的 Options 参数
5354
.defaultOptions(
54-
OllamaOptions.builder()
55+
OllamaChatOptions.builder()
5556
.topP(0.7)
5657
.model("llama3")
5758
.build()

0 commit comments

Comments
 (0)