x
This commit is contained in:
commit
12aa452792
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
91
pom.xml
Normal file
91
pom.xml
Normal file
@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.hxy</groupId>
|
||||
<artifactId>demoDeepSeek</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>demoDeepSeek</name>
|
||||
<description>demoDeepSeek</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<spring-boot.version>3.0.2</spring-boot.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<configuration>
|
||||
<mainClass>com.hxy.demodeepseek.DemoDeepSeekApplication</mainClass>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>repackage</id>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,12 @@
|
||||
package com.hxy.demodeepseek;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoDeepSeekApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoDeepSeekApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.hxy.demodeepseek.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "deepseek")
|
||||
@Data
|
||||
public class DeepSeekConfig {
|
||||
private String apiUrl;
|
||||
private String apiKey;
|
||||
}
|
25
src/main/java/com/hxy/demodeepseek/config/OpenAPIConfig.java
Normal file
25
src/main/java/com/hxy/demodeepseek/config/OpenAPIConfig.java
Normal file
@ -0,0 +1,25 @@
|
||||
package com.hxy.demodeepseek.config;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import io.swagger.v3.oas.models.ExternalDocumentation;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* http://localhost:8080/swagger-ui/index.html
|
||||
*/
|
||||
@Configuration
|
||||
public class OpenAPIConfig {
|
||||
@Bean
|
||||
public OpenAPI openAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("接口文档标题")
|
||||
.description("SpringBoot3 集成 Swagger3接口文档")
|
||||
.version("v1"))
|
||||
.externalDocs(new ExternalDocumentation()
|
||||
.description("项目API文档")
|
||||
.url("/"));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.hxy.demodeepseek.controller;
|
||||
import com.hxy.demodeepseek.service.DeepSeekService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
public class DeepSeekController {
|
||||
@Autowired
|
||||
private DeepSeekService deepSeekService;
|
||||
|
||||
@GetMapping("/chat")
|
||||
public Mono<String> sendChatRequest(String question) {
|
||||
Flux<String> response = deepSeekService.sendChatRequest(question);
|
||||
// 将 Flux 中的元素收集到一个列表中
|
||||
Mono<List<String>> listMono = response.collectList();
|
||||
|
||||
// 将列表中的元素拼接成一个字符串
|
||||
Mono<String> resultMono = listMono.map(list -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String str : list) {
|
||||
sb.append(str);
|
||||
}
|
||||
System.out.println("resultMono = " + sb);
|
||||
return sb.toString();
|
||||
});
|
||||
|
||||
return resultMono;
|
||||
}
|
||||
}
|
||||
|
17
src/main/java/com/hxy/demodeepseek/model/ChatRequest.java
Normal file
17
src/main/java/com/hxy/demodeepseek/model/ChatRequest.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.hxy.demodeepseek.model;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
@Data
|
||||
public class ChatRequest {
|
||||
private String model = "deepseek-ai/DeepSeek-V3";
|
||||
private List<Message> messages;
|
||||
private boolean stream = true;
|
||||
private int max_tokens = 2048;
|
||||
private double temperature = 0.7;
|
||||
private double top_p = 0.7;
|
||||
private int top_k = 50;
|
||||
private double frequency_penalty = 0.5;
|
||||
private int n = 1;
|
||||
private ResponseFormat response_format = new ResponseFormat("text");
|
||||
}
|
7
src/main/java/com/hxy/demodeepseek/model/Message.java
Normal file
7
src/main/java/com/hxy/demodeepseek/model/Message.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.hxy.demodeepseek.model;
|
||||
import lombok.Data;
|
||||
@Data
|
||||
public class Message {
|
||||
private String role;
|
||||
private String content;
|
||||
}
|
17
src/main/java/com/hxy/demodeepseek/model/ResponseFormat.java
Normal file
17
src/main/java/com/hxy/demodeepseek/model/ResponseFormat.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.hxy.demodeepseek.model;
|
||||
|
||||
public class ResponseFormat {
|
||||
private String type;
|
||||
|
||||
public ResponseFormat(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.hxy.demodeepseek.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.hxy.demodeepseek.config.DeepSeekConfig;
|
||||
import com.hxy.demodeepseek.model.ChatRequest;
|
||||
import com.hxy.demodeepseek.model.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.netty.http.client.PrematureCloseException;
|
||||
import reactor.util.retry.Retry;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
|
||||
@Service
|
||||
public class DeepSeekService {
|
||||
@Autowired
|
||||
private DeepSeekConfig config;
|
||||
@Autowired
|
||||
private WebClient.Builder webClientBuilder;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
|
||||
public Flux<String> sendChatRequest(String question) {
|
||||
ChatRequest request = new ChatRequest();
|
||||
Message userMessage = new Message();
|
||||
userMessage.setRole("user");
|
||||
userMessage.setContent(question);
|
||||
request.setMessages(Collections.singletonList(userMessage));
|
||||
|
||||
System.out.println("发送请求到: "+ config.getApiUrl());
|
||||
|
||||
return webClientBuilder.build()
|
||||
.post()
|
||||
.uri(config.getApiUrl())
|
||||
.header("Authorization", "Bearer " + config.getApiKey())
|
||||
.header("Content-Type", "application/json")
|
||||
.bodyValue(request)
|
||||
.retrieve()
|
||||
.bodyToFlux(String.class)
|
||||
.timeout(Duration.ofSeconds(300))
|
||||
.retryWhen(Retry.backoff(3, Duration.ofSeconds(2))
|
||||
.filter(throwable ->
|
||||
throwable instanceof PrematureCloseException
|
||||
|| throwable instanceof TimeoutException
|
||||
|| throwable instanceof RuntimeException)
|
||||
.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
|
||||
System.out.println("重试次数已用完,最后一次错误: "+ retrySignal.failure().getMessage());
|
||||
return new RuntimeException("服务暂时不可用,请稍后重试");
|
||||
}))
|
||||
.onErrorResume(e -> {
|
||||
System.out.println("请求处理错误: "+ e.getMessage());
|
||||
return Flux.just("抱歉,服务器处理请求时发生错误: " + e.getMessage());
|
||||
})
|
||||
.map(response -> {
|
||||
try {
|
||||
if ("[DONE]".equals(response)) {
|
||||
return "\n";
|
||||
}
|
||||
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
JsonNode choices = jsonNode.get("choices");
|
||||
if (choices != null && choices.isArray() && choices.size() > 0) {
|
||||
JsonNode choice = choices.get(0);
|
||||
JsonNode delta = choice.get("delta");
|
||||
if (delta != null && delta.has("content")) {
|
||||
String content = delta.get("content").asText();
|
||||
return content != null ? content : "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
} catch (Exception e) {
|
||||
System.out.println("解析响应时出错: "+ e.getMessage());
|
||||
System.out.println("原始响应: "+ response);
|
||||
return "";
|
||||
}
|
||||
})
|
||||
.filter(content -> !content.isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
|
10
src/main/resources/application.yml
Normal file
10
src/main/resources/application.yml
Normal file
@ -0,0 +1,10 @@
|
||||
spring:
|
||||
application:
|
||||
name: demoDeepSeek
|
||||
mvc:
|
||||
async:
|
||||
request-timeout: 360000
|
||||
deepseek:
|
||||
api-url: https://api.siliconflow.cn/v1/chat/completions
|
||||
api-key: sk-ldfhfwuwgskxzrskydasvjvqemctwonwuvqqfljaoomcjoro
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.hxy.demodeepseek;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class DemoDeepSeekApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user