Dify Java Client
1.7.0 adds stream completion and datasource callbacks, and fixes Chatflow terminal-event handling.
Dify Java Client is a Java client library for interacting with the Dify platform. It provides complete support for Dify Application APIs and Knowledge Base APIs, enabling Java developers to easily integrate Dify's generative AI capabilities into their applications.
Features
Dify Java Client provides the following core features:
1. Multiple Application Types Support
- Chat Applications: Interact with conversational applications via
DifyChatClient, supporting conversation management, message feedback, and more - Completion Applications: Call text generation applications via
DifyCompletionClient - Chatflow Applications: Call workflow-orchestrated conversational applications via
DifyChatflowClient - Workflow Applications: Call workflow applications via
DifyWorkflowClient - Knowledge Base Management: Manage knowledge bases, documents, and retrieval via
DifyDatasetsClient
2. Rich Interaction Modes
- Blocking Mode: Synchronous API calls, waiting for complete responses
- Streaming Mode: Receive real-time generated content through callbacks, supporting typewriter effects
- File Processing: Support for file uploads, speech-to-text, text-to-speech, and other multimedia functions
3. Complete Conversation Management
- Create and manage conversations
- Retrieve message history
- Rename conversations
- Message feedback (like/dislike)
- Get suggested questions
4. Full Knowledge Base Support
- Create and manage knowledge bases
- Upload and manage documents
- Document segment management
- Semantic retrieval
5. Flexible Configuration Options
- Custom connection timeout
- Custom read/write timeout
- Custom HTTP client
Installation
System Requirements
- Java 8 or higher
- Maven 3.x or Gradle 4.x+
Maven
<dependency>
<groupId>io.github.imfangs</groupId>
<artifactId>dify-java-client</artifactId>
<version>1.7.0</version>
</dependency>
Gradle
implementation 'io.github.imfangs:dify-java-client:1.7.0'
Quick Start
Creating Clients
// Create a complete Dify client
DifyClient client = DifyClientFactory.createClient("https://api.dify.ai/v1", "your-api-key");
// Create specific types of clients
DifyChatClient chatClient = DifyClientFactory.createChatClient("https://api.dify.ai/v1", "your-api-key");
DifyCompletionClient completionClient = DifyClientFactory.createCompletionClient("https://api.dify.ai/v1", "your-api-key");
DifyChatflowClient chatflowClient = DifyClientFactory.createChatWorkflowClient("https://api.dify.ai/v1", "your-api-key");
DifyWorkflowClient workflowClient = DifyClientFactory.createWorkflowClient("https://api.dify.ai/v1", "your-api-key");
DifyDatasetsClient datasetsClient = DifyClientFactory.createDatasetsClient("https://api.dify.ai/v1", "your-api-key");
// Create client with custom configuration
DifyConfig config = DifyConfig.builder()
.baseUrl("https://api.dify.ai/v1")
.apiKey("your-api-key")
.connectTimeout(5000)
.readTimeout(60000)
.writeTimeout(30000)
.build();
DifyClient clientWithConfig = DifyClientFactory.createClient(config);
Usage Examples
1. Chat Applications
Blocking Mode
// Create chat client
DifyChatClient chatClient = DifyClientFactory.createChatClient("https://api.dify.ai/v1", "your-api-key");
// Create chat message
ChatMessage message = ChatMessage.builder()
.query("Hello, please introduce yourself")
.user("user-123")
.responseMode(ResponseMode.BLOCKING)
.build();
// Send message and get response
ChatMessageResponse response = chatClient.sendChatMessage(message);
System.out.println("Reply: " + response.getAnswer());
System.out.println("Conversation ID: " + response.getConversationId());
System.out.println("Message ID: " + response.getMessageId());
Streaming Mode
// Create chat message
ChatMessage message = ChatMessage.builder()
.query("Please tell me a short story")
.user("user-123")
.responseMode(ResponseMode.STREAMING)
.build();
// Send streaming message
chatClient.sendChatMessageStream(message, new ChatStreamCallback() {
@Override
public void onMessage(MessageEvent event) {
System.out.println("Received message chunk: " + event.getAnswer());
}
@Override
public void onMessageEnd(MessageEndEvent event) {
System.out.println("Message ended, complete message ID: " + event.getMessageId());
}
@Override
public void onError(ErrorEvent event) {
System.err.println("Error: " + event.getMessage());
}
@Override
public void onException(Throwable throwable) {
System.err.println("Exception: " + throwable.getMessage());
}
});
Conversation Management
// Get conversation history messages
MessageListResponse messages = chatClient.getMessages(conversationId, "user-123", null, 10);
// Get conversation list
ConversationListResponse conversations = chatClient.getConversations("user-123", null, 10, "-updated_at");
// Rename conversation
Conversation renamedConversation = chatClient.renameConversation(conversationId, "New Conversation Name", false, "user-123");
// Delete conversation
SimpleResponse deleteResponse = chatClient.deleteConversation(conversationId, "user-123");
Message Feedback
// Send message feedback (like)
SimpleResponse feedbackResponse = chatClient.feedbackMessage(messageId, "like", "user-123", "This is a great answer");
// Get suggested questions
SuggestedQuestionsResponse suggestedQuestions = chatClient.getSuggestedQuestions(messageId, "user-123");
Voice Conversion
// Speech to text
AudioToTextResponse textResponse = chatClient.audioToText(audioFile, "user-123");
System.out.println("Converted text: " + textResponse.getText());
// Text to speech
byte[] audioData = chatClient.textToAudio(null, "This is a test text", "user-123");
2. Completion Applications
Blocking Mode
// Create completion client
DifyCompletionClient completionClient = DifyClientFactory.createCompletionClient("https://api.dify.ai/v1", "your-api-key");
// Create request
Map<String, Object> inputs = new HashMap<>();
inputs.put("content", "eggplant");
CompletionRequest request = CompletionRequest.builder()
.inputs(inputs)
.responseMode(ResponseMode.BLOCKING)
.user("user-123")
.build();
// Send request and get response
CompletionResponse response = completionClient.sendCompletionMessage(request);
System.out.println("Generated text: " + response.getAnswer());
Streaming Mode
// Create request
Map<String, Object> inputs = new HashMap<>();
inputs.put("content", "eggplant");
CompletionRequest request = CompletionRequest.builder()
.inputs(inputs)
.responseMode(ResponseMode.STREAMING)
.user("user-123")
.build();
// Send streaming request
completionClient.sendCompletionMessageStream(request, new CompletionStreamCallback() {
@Override
public void onMessage(MessageEvent event) {
System.out.println("Received message chunk: " + event.getAnswer());
}
@Override
public void onMessageEnd(MessageEndEvent event) {
System.out.println("Message ended, complete message ID: " + event.getMessageId());
}
@Override
public void onError(ErrorEvent event) {
System.err.println("Error: " + event.getMessage());
}
@Override
public void onException(Throwable throwable) {
System.err.println("Exception: " + throwable.getMessage());
}
});
Stop Generation
// Stop text generation
SimpleResponse stopResponse = completionClient.stopCompletion(taskId, "user-123");
3. Workflow Applications
Blocking Mode
// Create workflow client
DifyWorkflowClient workflowClient = DifyClientFactory.createWorkflowClient("https://api.dify.ai/v1", "your-api-key");
// Create workflow request
Map<String, Object> inputs = new HashMap<>();
inputs.put("content", "Please introduce AI application scenarios");
WorkflowRunRequest request = WorkflowRunRequest.builder()
.inputs(inputs)
.responseMode(ResponseMode.BLOCKING)
.user("user-123")
.build();
// Run workflow and get response
WorkflowRunResponse response = workflowClient.runWorkflow(request);
System.out.println("Workflow execution ID: " + response.getTaskId());
// Output results
if (response.getData() != null) {
for (Map.Entry<String, Object> entry : response.getData().getOutputs().entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
Streaming Mode
// Create workflow request
Map<String, Object> inputs = new HashMap<>();
inputs.put("content", "Please explain the basic principles of machine learning in detail");
WorkflowRunRequest request = WorkflowRunRequest.builder()
.inputs(inputs)
.responseMode(ResponseMode.STREAMING)
.user("user-123")
.build();
// Run workflow streaming request
workflowClient.runWorkflowStream(request, new WorkflowStreamCallback() {
@Override
public void onWorkflowStarted(WorkflowStartedEvent event) {
System.out.println("Workflow started: " + event);
}
@Override
public void onNodeStarted(NodeStartedEvent event) {
System.out.println("Node started: " + event);
}
@Override
public void onNodeFinished(NodeFinishedEvent event) {
System.out.println("Node finished: " + event);
}
@Override
public void onWorkflowFinished(WorkflowFinishedEvent event) {
System.out.println("Workflow finished: " + event);
}
@Override
public void onError(ErrorEvent event) {
System.err.println("Error: " + event.getMessage());
}
@Override
public void onException(Throwable throwable) {
System.err.println("Exception: " + throwable.getMessage());
}
});
Workflow Management
// Stop workflow
WorkflowStopResponse stopResponse = workflowClient.stopWorkflow(taskId, "user-123");
// Get workflow execution status
WorkflowRunStatusResponse statusResponse = workflowClient.getWorkflowRun(workflowRunId);
// Get workflow logs
WorkflowLogsResponse logsResponse = workflowClient.getWorkflowLogs(null, null, 1, 10);
4. Knowledge Base Management
Create and Manage Knowledge Bases
// Create datasets client
DifyDatasetsClient datasetsClient = DifyClientFactory.createDatasetsClient("https://api.dify.ai/v1", "your-api-key");
// Create knowledge base
CreateDatasetRequest createRequest = CreateDatasetRequest.builder()
.name("Test Knowledge Base-" + System.currentTimeMillis())
.description("This is a test knowledge base")
.indexingTechnique("high_quality")
.permission("only_me")
.provider("vendor")
.build();
DatasetResponse dataset = datasetsClient.createDataset(createRequest);
System.out.println("Created knowledge base ID: " + dataset.getId());
// Get knowledge base list
DatasetListResponse datasetList = datasetsClient.getDatasets(1, 10);
System.out.println("Total knowledge bases: " + datasetList.getTotal());
Document Management
// Create document by text - Using automatic mode (recommended)
CreateDocumentByTextRequest docRequest = CreateDocumentByTextRequest.builder()
.name("Test Document-" + System.currentTimeMillis())
.text("This is the content of a test document.\nThis is the second line.\nThis is the third line.")
.indexingTechnique("high_quality")
.docForm("text_model")
.docLanguage("English")
.processRule(ProcessRule.builder()
.mode("automatic") // Use automatic processing mode
.build())
.build();
DocumentResponse docResponse = datasetsClient.createDocumentByText(datasetId, docRequest);
System.out.println("Created document ID: " + docResponse.getDocument().getId());
// Get document list
DocumentListResponse docList = datasetsClient.getDocuments(datasetId, null, 1, 10);
System.out.println("Total documents: " + docList.getTotal());
// Delete document
SimpleResponse deleteResponse = datasetsClient.deleteDocument(datasetId, documentId);
Knowledge Base Retrieval
// Create retrieval request
RetrievalModel retrievalModel = new RetrievalModel();
retrievalModel.setTopK(3);
retrievalModel.setScoreThreshold(0.5f);
RetrieveRequest retrieveRequest = RetrieveRequest.builder()
.query("What is artificial intelligence")
.retrievalModel(retrievalModel)
.build();
// Send retrieval request
RetrieveResponse retrieveResponse = datasetsClient.retrieveDataset(datasetId, retrieveRequest);
// Process retrieval results
System.out.println("Retrieval query: " + retrieveResponse.getQuery().getContent());
System.out.println("Number of retrieval results: " + retrieveResponse.getRecords().size());
retrieveResponse.getRecords().forEach(record -> {
System.out.println("Score: " + record.getScore());
System.out.println("Content: " + record.getSegment().getContent());
});
Document Download
// Single document: get a signed download URL
DocumentDownloadUrlResponse url = datasetsClient.getDocumentDownloadUrl(datasetId, documentId);
// Batch: up to 100 documents packed into a ZIP archive
DocumentBatchDownloadRequest batchRequest = DocumentBatchDownloadRequest.builder()
.documentIds(java.util.Arrays.asList(documentId1, documentId2))
.build();
try (FilePreviewResponse zip = datasetsClient.downloadDocumentsAsZip(datasetId, batchRequest)) {
java.nio.file.Files.write(java.nio.file.Paths.get(zip.getFileName()), zip.getContentAsBytes());
}
Knowledge Pipeline (RAG Pipeline)
// 1) List datasource nodes configured in the pipeline
List<DatasourcePluginResponse> nodes = datasetsClient.listPipelineDatasourcePlugins(datasetId, true);
String startNodeId = nodes.stream()
.filter(node -> "local_file".equals(node.getDatasourceType()))
.findFirst().orElseThrow(() -> new IllegalStateException("Configure a local_file node first"))
.getNodeId();
// 2) Upload a file for pipeline processing
PipelineFileUploadResponse uploaded = datasetsClient.uploadPipelineFile(new java.io.File("./doc.pdf"));
// 3) Submit the published pipeline (returns a JSON queue receipt)
java.util.Map<String, Object> item = new java.util.HashMap<>();
item.put("reference", uploaded.getId());
item.put("name", uploaded.getName());
PipelineRunRequest runRequest = PipelineRunRequest.builder()
.inputs(new java.util.HashMap<>())
.datasourceType("local_file")
.datasourceInfoList(java.util.Arrays.asList(item))
.startNodeId(startNodeId)
.isPublished(true)
.build();
java.util.Map<String, Object> result = datasetsClient.runPipeline(datasetId, runRequest);
// SSE is supported for draft pipelines; draft node IDs may differ
String draftStartNodeId = datasetsClient.listPipelineDatasourcePlugins(datasetId, false).stream()
.filter(node -> "local_file".equals(node.getDatasourceType()))
.findFirst().orElseThrow(() -> new IllegalStateException("Configure a draft local_file node first"))
.getNodeId();
PipelineRunRequest draftRequest = PipelineRunRequest.builder()
.inputs(new java.util.HashMap<>())
.datasourceType("local_file")
.datasourceInfoList(java.util.Arrays.asList(item))
.startNodeId(draftStartNodeId)
.isPublished(false)
.build();
datasetsClient.runPipelineStream(datasetId, draftRequest, callback);
// 4) Run a configured online_drive node (callbacks below require 1.7.0)
DatasourcePluginResponse driveNode = nodes.stream()
.filter(node -> "online_drive".equals(node.getDatasourceType()))
.findFirst().orElseThrow(() -> new IllegalStateException("Configure an online_drive node first"));
java.util.Map<String, Object> driveInputs = new java.util.HashMap<>();
// Fill inputs required by driveNode.getUserInputVariables(); configure credentials in Dify first
DatasourceNodeRunRequest nodeRequest = DatasourceNodeRunRequest.builder()
.inputs(driveInputs)
.datasourceType("online_drive")
.isPublished(true)
.build();
datasetsClient.runPipelineDatasourceNodeStream(datasetId, driveNode.getNodeId(), nodeRequest,
new WorkflowStreamCallback() {
@Override
public void onDatasourceCompleted(DatasourceCompletedEvent event) {
System.out.println(event.getData());
}
@Override
public void onDatasourceError(DatasourceErrorEvent event) {
System.err.println(event.getError());
}
@Override
public void onStreamComplete() {
System.out.println("Stream complete");
}
});
5. End Users
// Retrieve end-user details by ID (e.g., when created_by from other APIs is an end-user ID)
EndUserResponse endUser = client.getEndUser(endUserId);
System.out.println("external_user_id: " + endUser.getExternalUserId());
6. Human Input Flow
Dify 1.14.2+ supports inserting Human Input nodes into workflow/chatflow apps that pause execution and wait for a form submission.
Enable WebApp delivery on the Human Input node to retrieve and submit forms through this API; other approval channels may not provide a form_token.
// 1) Subscribe to a workflow; onHumanInputRequired fires when the run reaches a human-input node
workflowClient.runWorkflowStream(request, new WorkflowStreamCallback() {
@Override
public void onHumanInputRequired(HumanInputRequiredEvent event) {
String formToken = event.getData().getFormToken();
String workflowRunId = event.getWorkflowRunId();
handoffToReviewer(formToken, workflowRunId);
}
});
// 2) Fetch the paused form
HumanInputFormResponse form = client.getHumanInputForm(formToken);
// 3) Submit the form to resume the workflow
java.util.Map<String, Object> inputs = new java.util.HashMap<>();
inputs.put("decision", "approve");
HumanInputFormSubmitRequest submit = HumanInputFormSubmitRequest.builder()
.inputs(inputs)
.action("action-approve")
.user("reviewer-alice")
.build();
client.submitHumanInputForm(formToken, submit);
// 4) Re-subscribe to the resumed workflow events
// Resume using the original run user, not the reviewer identity
workflowClient.streamWorkflowEvents(workflowRunId, request.getUser(), true, false, callback);
7. Reasoning Chunk
When a Chatflow LLM node uses reasoning_format=separated, the model's chain-of-thought streams as reasoning_chunk events parallel to the answer.
chatflowClient.sendChatMessageStream(message, new ChatflowStreamCallback() {
@Override
public void onReasoningChunk(ReasoningChunkEvent event) {
renderThinking(event.getData().getReasoning(),
Boolean.TRUE.equals(event.getData().getIsFinal()));
}
});
API Reference
Client Types
| Client Type | Description | Main Features |
|---|---|---|
DifyClient |
Complete client | Supports all API features |
DifyChatClient |
Chat application client | Conversations, conversation management, message feedback |
DifyCompletionClient |
Text generation application client | Text generation, stop generation |
DifyChatflowClient |
Workflow-orchestrated chat application client | Workflow-orchestrated conversations |
DifyWorkflowClient |
Workflow application client | Execute workflows, workflow management |
DifyDatasetsClient |
Knowledge base client | Knowledge base management, document management, retrieval, batch/signed download, RAG Pipeline |
Response Modes
| Mode | Enum Value | Description |
|---|---|---|
| Blocking Mode | ResponseMode.BLOCKING |
Synchronous call, waiting for complete response |
| Streaming Mode | ResponseMode.STREAMING |
Receive real-time generated content through callbacks |
Event Types
| Event Type | Description |
|---|---|
MessageEvent |
Message event, containing generated text chunk |
MessageEndEvent |
Message end event, containing complete message ID |
MessageFileEvent |
File message event, containing file information |
TtsMessageEvent |
Text-to-speech event |
TtsMessageEndEvent |
Text-to-speech end event |
MessageReplaceEvent |
Message replacement event |
AgentMessageEvent |
Agent message event |
AgentThoughtEvent |
Agent thought event |
ReasoningChunkEvent |
LLM reasoning stream event (reasoning_format=separated) |
WorkflowStartedEvent |
Workflow started event |
NodeStartedEvent |
Node started event |
NodeFinishedEvent |
Node finished event |
NodeRetryEvent |
Node retry event |
WorkflowFinishedEvent |
Workflow finished event |
WorkflowPausedEvent |
Workflow paused (human input) event |
HumanInputRequiredEvent |
Human input required event |
HumanInputFormFilledEvent |
Human input form submitted event |
HumanInputFormTimeoutEvent |
Human input form timeout event |
ErrorEvent |
Error event |
PingEvent |
Ping event |
Advanced Configuration
Custom HTTP Client
// Create custom configuration
DifyConfig config = DifyConfig.builder()
.baseUrl("https://api.dify.ai/v1")
.apiKey("your-api-key")
.connectTimeout(5000) // Connection timeout (milliseconds)
.readTimeout(60000) // Read timeout (milliseconds)
.writeTimeout(30000) // Write timeout (milliseconds)
.build();
// Create client with custom configuration
DifyClient client = DifyClientFactory.createClient(config);
More Documentation
-
- Message sending (blocking/streaming)
- Conversation management
- Message feedback
- Voice conversion
- Suggested questions
-
Completion Application API Examples
- Text generation (blocking/streaming)
- Stop generation
- File processing
- Text to speech
-
Workflow Application API Examples
- Workflow execution (blocking/streaming)
- Stop workflow
- Workflow status
- Workflow logs
-
- Knowledge base management
- Document management
- Semantic retrieval
-
- Message events
- File events
- TTS events
- Workflow events
- Error handling
Development and verification
The current version is 1.7.0, as used in the installation examples above. Building requires Maven 3.9.2+; CI is configured for JDK 8, 17, 21, 25 and 26.
mvn -B -ntp clean verify
The default build runs local regression tests without Dify credentials or GPG.
Real-service examples carry the integration tag. Configure a dedicated test
environment in src/test/resources/dify-test-config.properties, then explicitly
run mvn -Pintegration-tests test. These tests create, modify or delete Dify data.
Since 1.7.0, onStreamComplete() reports normal stream termination after both
Chatflow terminal events, or server EOF. It does not assert business success;
API errors, transport failures and parsing errors do not trigger completion.
Datasource nodes report onDatasourceProcessing, onDatasourceCompleted and
onDatasourceError; completion events may occur once per page before EOF.
See CURRENT.md for contract sources and verification limits.
See Publishing from another computer for Actions and credential recovery.
Contributing
Contributions of code, issue reports, or improvement suggestions are welcome. Please participate in project development through GitHub Issues or Pull Requests.
License
This project is licensed under the Apache License 2.0.