├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── pitayafruit
│ │ ├── DifyDemoApplication.java
│ │ ├── controller
│ │ └── TestController.java
│ │ ├── req
│ │ └── DifyRequestBody.java
│ │ ├── resp
│ │ ├── BlockResponse.java
│ │ └── StreamResponse.java
│ │ └── service
│ │ └── DifyService.java
└── resources
│ └── application.yml
└── test
└── java
└── com
└── pitayafruit
└── DifyDemoApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 项目说明
2 | 基于SpringBoot封装了调用Dify服务的API
3 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.3.2
9 |
10 |
11 | com.pitayafruit
12 | dify-demo
13 | 0.0.1-SNAPSHOT
14 | dify-demo
15 | dify-demo
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 17
31 |
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-web
37 |
38 |
39 |
40 | org.projectlombok
41 | lombok
42 |
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-webflux
47 |
48 |
49 |
50 | com.alibaba.fastjson2
51 | fastjson2
52 | 2.0.52
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-test
58 | test
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-maven-plugin
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/main/java/com/pitayafruit/DifyDemoApplication.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.web.client.RestTemplate;
7 | import org.springframework.web.reactive.function.client.WebClient;
8 |
9 | @SpringBootApplication
10 | public class DifyDemoApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(DifyDemoApplication.class, args);
14 | }
15 |
16 | @Bean
17 | public RestTemplate restTemplate() {
18 | return new RestTemplate();
19 | }
20 |
21 | @Bean
22 | public WebClient webClient() {
23 | return WebClient.create();
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/pitayafruit/controller/TestController.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit.controller;
2 |
3 | import com.pitayafruit.resp.BlockResponse;
4 | import com.pitayafruit.resp.StreamResponse;
5 | import com.pitayafruit.service.DifyService;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import reactor.core.publisher.Flux;
12 |
13 | @RestController
14 | @RequestMapping("/api/test")
15 | @RequiredArgsConstructor
16 | public class TestController {
17 |
18 | @Value("${dify.key.test}")
19 | private String testKey;
20 |
21 | private final DifyService difyService;
22 |
23 | @GetMapping("/block")
24 | public String test1() {
25 | String query = "鲁迅和周树人什么关系?";
26 | BlockResponse blockResponse = difyService.blockingMessage(query, 0L, testKey);
27 | return blockResponse.getAnswer();
28 | }
29 |
30 | @GetMapping("/stream")
31 | public Flux test2() {
32 | String query = "鲁迅和周树人什么关系?";
33 | return difyService.streamingMessage(query, 0L, testKey);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/pitayafruit/req/DifyRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit.req;
2 |
3 | import com.alibaba.fastjson2.annotation.JSONField;
4 | import java.io.Serializable;
5 | import java.util.Map;
6 | import lombok.Data;
7 |
8 | /**
9 | * Dify请求体.
10 | */
11 | @Data
12 | public class DifyRequestBody implements Serializable {
13 |
14 | /**
15 | * 用户输入/提问内容.
16 | */
17 | private String query;
18 |
19 | /**
20 | * 允许传入 App 定义的各变量值.
21 | */
22 | private Map inputs;
23 |
24 | /**
25 | * 响应模式,streaming 流式,blocking 阻塞.
26 | */
27 | @JSONField(name = "response_mode")
28 | private String responseMode;
29 |
30 | /**
31 | * 用户标识.
32 | */
33 | private String user;
34 |
35 | /**
36 | * 会话id.
37 | */
38 | @JSONField(name = "conversation_id")
39 | private String conversationId;
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/pitayafruit/resp/BlockResponse.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit.resp;
2 |
3 | import java.io.Serializable;
4 | import java.util.Map;
5 | import lombok.Data;
6 |
7 | /**
8 | * Dify阻塞式调用响应.
9 | */
10 | @Data
11 | public class BlockResponse implements Serializable {
12 |
13 | /**
14 | * 不同模式下的事件类型.
15 | */
16 | private String event;
17 |
18 | /**
19 | * 消息唯一 ID.
20 | */
21 | private String messageId;
22 |
23 | /**
24 | * 任务ID.
25 | */
26 | private String taskId;
27 |
28 | /**
29 | * agent_thought id.
30 | */
31 | private String id;
32 |
33 | /**
34 | * 会话 ID.
35 | */
36 | private String conversationId;
37 |
38 | /**
39 | * App 模式,固定为 chat.
40 | */
41 | private String mode;
42 |
43 | /**
44 | * 完整回复内容.
45 | */
46 | private String answer;
47 |
48 | /**
49 | * 元数据.
50 | */
51 | private Map> metadata;
52 |
53 | /**
54 | * 创建时间戳.
55 | */
56 | private Long createdAt;
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/pitayafruit/resp/StreamResponse.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit.resp;
2 |
3 | import java.io.Serializable;
4 | import lombok.Data;
5 |
6 |
7 | /**
8 | * Dify流式调用响应.
9 | */
10 | @Data
11 | public class StreamResponse implements Serializable {
12 |
13 | /**
14 | * 不同模式下的事件类型.
15 | */
16 | private String event;
17 |
18 | /**
19 | * agent_thought id.
20 | */
21 | private String id;
22 |
23 | /**
24 | * 任务ID.
25 | */
26 | private String taskId;
27 |
28 | /**
29 | * 消息唯一ID.
30 | */
31 | private String messageId;
32 |
33 | /**
34 | * LLM 返回文本块内容.
35 | */
36 | private String answer;
37 |
38 | /**
39 | * 创建时间戳.
40 | */
41 | private Long createdAt;
42 |
43 | /**
44 | * 会话 ID.
45 | */
46 | private String conversationId;
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/pitayafruit/service/DifyService.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit.service;
2 |
3 | import com.alibaba.fastjson2.JSON;
4 | import com.pitayafruit.req.DifyRequestBody;
5 | import com.pitayafruit.resp.BlockResponse;
6 | import com.pitayafruit.resp.StreamResponse;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import lombok.RequiredArgsConstructor;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.http.HttpEntity;
12 | import org.springframework.http.HttpHeaders;
13 | import org.springframework.http.MediaType;
14 | import org.springframework.http.ResponseEntity;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.web.client.RestTemplate;
17 | import org.springframework.web.reactive.function.client.WebClient;
18 | import reactor.core.publisher.Flux;
19 |
20 |
21 | @Service
22 | @RequiredArgsConstructor
23 | public class DifyService {
24 |
25 | @Value("${dify.url}")
26 | private String url;
27 |
28 | private final RestTemplate restTemplate;
29 |
30 | private final WebClient webClient;
31 |
32 | /**
33 | * 流式调用dify.
34 | *
35 | * @param query 查询文本
36 | * @param userId 用户id
37 | * @param apiKey apiKey 通过 apiKey 获取权限并区分不同的 dify 应用
38 | * @return Flux 响应流
39 | */
40 | public Flux streamingMessage(String query, Long userId, String apiKey) {
41 | //1.设置请求体
42 | DifyRequestBody body = new DifyRequestBody();
43 | body.setInputs(new HashMap<>());
44 | body.setQuery(query);
45 | body.setResponseMode("streaming");
46 | body.setConversationId("");
47 | body.setUser(userId.toString());
48 | //2.使用webclient发送post请求
49 | return webClient.post()
50 | .uri(url)
51 | .headers(httpHeaders -> {
52 | httpHeaders.setContentType(MediaType.APPLICATION_JSON);
53 | httpHeaders.setBearerAuth(apiKey);
54 | })
55 | .bodyValue(JSON.toJSONString(body))
56 | .retrieve()
57 | .bodyToFlux(StreamResponse.class);
58 | }
59 |
60 |
61 | /**
62 | * 阻塞式调用dify.
63 | *
64 | * @param query 查询文本
65 | * @param userId 用户id
66 | * @param apiKey apiKey 通过 apiKey 获取权限并区分不同的 dify 应用
67 | * @return BlockResponse
68 | */
69 | public BlockResponse blockingMessage(String query, Long userId, String apiKey) {
70 | //1.设置请求体
71 | DifyRequestBody body = new DifyRequestBody();
72 | body.setInputs(new HashMap<>());
73 | body.setQuery(query);
74 | body.setResponseMode("blocking");
75 | body.setConversationId("");
76 | body.setUser(userId.toString());
77 | //2.设置请求头
78 | HttpHeaders headers = new HttpHeaders();
79 | headers.setContentType(MediaType.APPLICATION_JSON);
80 | headers.setAccept(List.of(MediaType.APPLICATION_JSON));
81 | headers.setBearerAuth(apiKey);
82 | //3.封装请求体和请求头
83 | String jsonString = JSON.toJSONString(body);
84 | HttpEntity entity = new HttpEntity<>(jsonString, headers);
85 | //4.发送post请求,阻塞式
86 | ResponseEntity stringResponseEntity =
87 | restTemplate.postForEntity(url, entity, BlockResponse.class);
88 | //5.返回响应体
89 | return stringResponseEntity.getBody();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: dify-demo
4 |
5 | dify:
6 | url: http://localhost/v1/chat-messages
7 | key:
8 | test: app-y67TVu9T8tZ6r2UUMBJ6wm8R
9 |
10 |
--------------------------------------------------------------------------------
/src/test/java/com/pitayafruit/DifyDemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.pitayafruit;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class DifyDemoApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------