@ifzai/connect2dify
Version:
A comprehensive TypeScript client for the Dify API, providing a clean and modular interface for chat, workflow, file management, and application interactions.
669 lines (668 loc) • 23.7 kB
JavaScript
"use strict";
var __webpack_require__ = {};
(()=>{
__webpack_require__.d = (exports1, definition)=>{
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
enumerable: true,
get: definition[key]
});
};
})();
(()=>{
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
__webpack_require__.r = (exports1)=>{
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
value: 'Module'
});
Object.defineProperty(exports1, '__esModule', {
value: true
});
};
})();
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
DifyClient: ()=>DifyClient,
MIME_MAP: ()=>MIME_MAP,
buildURL: ()=>buildURL,
AppAPI: ()=>AppAPI,
FileAPI: ()=>FileAPI,
createHeaders: ()=>createHeaders,
handleResponse: ()=>handleResponse,
ConversationAPI: ()=>ConversationAPI,
handleStreamResponse: ()=>handleStreamResponse,
Client: ()=>Client,
WorkflowAPI: ()=>WorkflowAPI,
parseSSEChunk: ()=>parseSSEChunk,
ChatAPI: ()=>ChatAPI
});
function createHeaders(apiKey, extraHeaders = {}, includeContentType = true) {
const headers = {
Authorization: `Bearer ${apiKey}`,
...extraHeaders
};
if (includeContentType) headers['Content-Type'] = 'application/json';
return headers;
}
async function handleResponse(response) {
if (!response.ok) throw new Error(`Request failed: ${response.status} ${response.statusText}`);
return response.json();
}
function parseSSEChunk(chunkData) {
if (!chunkData.trim().startsWith('data:')) return null;
try {
return JSON.parse(chunkData.replace(/^data: /, ''));
} catch (error) {
console.error('Failed to parse chunk:', chunkData);
throw new Error(`Invalid chunk format: ${chunkData}`);
}
}
function processSSEBuffer(buffer, chunks, onChunk) {
const splitMark = '\n\n';
let remainingBuffer = buffer;
while(true){
const chunkEnd = remainingBuffer.indexOf(splitMark);
if (-1 === chunkEnd) break;
const chunkData = remainingBuffer.slice(0, chunkEnd + splitMark.length);
remainingBuffer = remainingBuffer.slice(chunkEnd + splitMark.length);
const chunk = parseSSEChunk(chunkData);
if (chunk) {
chunks.push(chunk);
onChunk?.(chunk);
}
}
return remainingBuffer;
}
async function handleStreamResponse(response, onChunk) {
if (!response.body) throw new Error('Response body is empty');
const reader = response.body.getReader();
const chunks = [];
let buffer = '';
try {
while(true){
const { done, value } = await reader.read();
if (value) {
buffer += new TextDecoder().decode(value, {
stream: true
});
buffer = processSSEBuffer(buffer, chunks, onChunk);
}
if (done) {
processSSEBuffer(buffer, chunks, onChunk);
break;
}
}
} finally{
reader.releaseLock();
}
return chunks;
}
function isStreamingSupported() {
try {
return 'undefined' != typeof ReadableStream && new Response(new ReadableStream()).body?.getReader() !== void 0;
} catch {
return false;
}
}
function createFormData(params) {
const formData = new FormData();
formData.append('file', params.file);
formData.append('user', params.user);
return formData;
}
function buildURL(baseUrl, path, params = {}) {
let fullUrl;
if (path.startsWith('/')) fullUrl = `${baseUrl}${path}`;
else {
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
fullUrl = `${normalizedBaseUrl}${path}`;
}
if (Object.keys(params).length > 0) {
const queryParams = new URLSearchParams();
for (const [key, value] of Object.entries(params))if (null != value) queryParams.set(key, value);
const queryString = queryParams.toString();
if (queryString) fullUrl += `?${queryString}`;
}
return fullUrl;
}
class AppAPI {
config;
constructor(config){
this.config = config;
}
async getParameters() {
const url = buildURL(this.config.baseUrl, 'parameters');
const response = await fetch(url, {
method: 'GET',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false)
});
return handleResponse(response);
}
async getInfo() {
const url = buildURL(this.config.baseUrl, 'info');
const response = await fetch(url, {
method: 'GET',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false)
});
return handleResponse(response);
}
async getMeta() {
const url = buildURL(this.config.baseUrl, 'meta');
const response = await fetch(url, {
method: 'GET',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false)
});
return handleResponse(response);
}
async sendCompletionMessage(params) {
const url = buildURL(this.config.baseUrl, 'completion-messages');
const body = {
inputs: params.inputs || {},
response_mode: params.response_mode,
user: params.user,
files: params.files
};
if ('blocking' === params.response_mode) {
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify(body)
});
return handleResponse(response);
}
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify(body)
});
if (!response.ok) throw new Error(`Request failed: ${response.status} ${response.statusText}`);
return handleStreamResponse(response, params.chunkCompletionCallback);
}
async stopCompletionMessage(params) {
const url = buildURL(this.config.baseUrl, `completion-messages/${params.task_id}/stop`);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify({
user: params.user
})
});
return handleResponse(response);
}
}
class ChatAPI {
config;
constructor(config){
this.config = config;
}
async sendMessage(params) {
const url = buildURL(this.config.baseUrl, 'chat-messages');
const body = {
inputs: {},
...params
};
if ('streaming' === params.response_mode) return this.handleChatStream(url, body, params);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify(body)
});
return handleResponse(response);
}
async getMessages(params) {
const queryParams = {
conversation_id: params.conversation_id,
user: params.user
};
if (params.first_id) queryParams.first_id = params.first_id;
if (params.limit) queryParams.limit = String(params.limit);
const url = buildURL(this.config.baseUrl, 'messages', queryParams);
const response = await fetch(url, {
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false),
method: 'GET'
});
return handleResponse(response);
}
async createMessageFeedback(params) {
const url = buildURL(this.config.baseUrl, `messages/${params.message_id}/feedbacks`);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify({
rating: params.rating,
user: params.user,
content: params.content
})
});
return handleResponse(response);
}
async getMessageSuggests(params) {
const queryParams = {
user: params.user
};
const url = buildURL(this.config.baseUrl, `messages/${params.message_id}/suggested`, queryParams);
const response = await fetch(url, {
method: 'GET',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders)
});
return handleResponse(response);
}
async stopMessageResponse(params) {
const url = buildURL(this.config.baseUrl, `chat-messages/${params.task_id}/stop`);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify({
user: params.user
})
});
return handleResponse(response);
}
async handleChatStream(url, body, params) {
const extraHeaders = this.config.requestOptions?.extraHeaders || {};
if (!isStreamingSupported()) throw new Error('Streaming is not supported in this environment. Please use blocking mode instead.');
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, extraHeaders),
body: JSON.stringify(body)
});
if (!response.ok) throw new Error(`Request failed: ${response.status} ${response.statusText}`);
return handleStreamResponse(response, params.chunkCompletionCallback);
}
}
class ConversationAPI {
config;
constructor(config){
this.config = config;
}
async getConversations(params) {
const queryParams = {
user: params.user
};
if (params.last_id) queryParams.last_id = params.last_id;
if (params.limit) queryParams.limit = String(params.limit);
if (params.sort_by) queryParams.sort_by = params.sort_by;
const url = buildURL(this.config.baseUrl, 'conversations', queryParams);
const response = await fetch(url, {
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false),
method: 'GET'
});
return handleResponse(response);
}
async deleteConversation(params) {
const url = buildURL(this.config.baseUrl, `conversations/${params.conversation_id}`);
const response = await fetch(url, {
method: 'DELETE',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify({
user: params.user
})
});
return handleResponse(response);
}
async renameConversation(params) {
const url = buildURL(this.config.baseUrl, `conversations/${params.conversation_id}/name`);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify({
name: params.name,
auto_generate: params.auto_generate,
user: params.user
})
});
return handleResponse(response);
}
}
class FileAPI {
config;
constructor(config){
this.config = config;
}
async uploadFile(params) {
const url = buildURL(this.config.baseUrl, 'files/upload');
const formData = createFormData(params);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false),
body: formData
});
return handleResponse(response);
}
async audioToText(params) {
const url = buildURL(this.config.baseUrl, 'audio-to-text');
const formData = createFormData(params);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders, false),
body: formData
});
return handleResponse(response);
}
async textToAudio(params) {
const url = buildURL(this.config.baseUrl, 'text-to-audio');
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify(params)
});
if (!response.ok) throw new Error(`Request failed: ${response.status} ${response.statusText}`);
return response.blob();
}
}
class WorkflowAPI {
config;
constructor(config){
this.config = config;
}
async runWorkflow(params) {
const url = buildURL(this.config.baseUrl, 'workflows/run');
const isStreaming = 'streaming' === params.response_mode;
if (isStreaming) return this.handleWorkflowStream(params, url);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify(params)
});
return handleResponse(response);
}
async getWorkflow(params) {
const url = buildURL(this.config.baseUrl, `workflows/run/${params.workflow_run_id}`);
const response = await fetch(url, {
method: 'GET',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders)
});
return handleResponse(response);
}
async stopWorkflowTask(params) {
const url = buildURL(this.config.baseUrl, `workflows/tasks/${params.task_id}/stop`);
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify({
user: params.user
})
});
return handleResponse(response);
}
async getWorkflowLogs(params) {
const queryParams = {};
if (params.keyword) queryParams.keyword = params.keyword;
if (params.status) queryParams.status = params.status;
if (params.page) queryParams.page = String(params.page);
if (params.limit) queryParams.limit = String(params.limit);
const url = buildURL(this.config.baseUrl, 'workflows/logs', queryParams);
const response = await fetch(url, {
method: 'GET',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders)
});
return handleResponse(response);
}
async handleWorkflowStream(params, url) {
const response = await fetch(url, {
method: 'POST',
headers: createHeaders(this.config.apiKey, this.config.requestOptions?.extraHeaders),
body: JSON.stringify(params)
});
if (!response.ok || !response.body) throw new Error(`Workflow failed: ${response.status} ${response.statusText}`);
return handleStreamResponse(response, params.chunkCompletionCallback);
}
}
class DifyClient {
config;
chat;
conversation;
workflow;
file;
app;
constructor(config){
this.config = {
baseUrl: config.baseUrl,
apiKey: config.apiKey,
defaultResponseMode: config.defaultResponseMode || 'blocking',
defaultUser: config.defaultUser,
requestOptions: config.requestOptions
};
this.chat = new ChatAPI(this.config);
this.conversation = new ConversationAPI(this.config);
this.workflow = new WorkflowAPI(this.config);
this.file = new FileAPI(this.config);
this.app = new AppAPI(this.config);
}
updateConfig(newConfig) {
this.config = {
...this.config,
...newConfig
};
Object.assign(this.chat, new ChatAPI(this.config));
Object.assign(this.conversation, new ConversationAPI(this.config));
Object.assign(this.workflow, new WorkflowAPI(this.config));
Object.assign(this.file, new FileAPI(this.config));
Object.assign(this.app, new AppAPI(this.config));
}
getConfig() {
return {
...this.config
};
}
async sendMessage(params) {
const result = await this.chat.sendMessage(params);
if (Array.isArray(result)) throw new Error('Use sendMessageStream for streaming responses');
return result;
}
async sendMessageStream(params) {
const streamParams = {
...params,
response_mode: 'streaming'
};
const result = await this.chat.sendMessage(streamParams);
if (!Array.isArray(result)) throw new Error('Expected streaming response');
return async function*() {
for (const chunk of result)yield chunk;
}();
}
async stopMessage(params) {
return this.chat.stopMessageResponse(params);
}
async createMessageFeedback(params) {
return this.chat.createMessageFeedback(params);
}
async getMessageSuggests(params) {
return this.chat.getMessageSuggests(params);
}
async getConversations(params) {
return this.conversation.getConversations(params);
}
async deleteConversation(params) {
return this.conversation.deleteConversation(params);
}
async renameConversation(params) {
return this.conversation.renameConversation(params);
}
async getMessages(params) {
return this.chat.getMessages(params);
}
async runWorkflow(params) {
const result = await this.workflow.runWorkflow(params);
if (Array.isArray(result)) throw new Error('Use runWorkflowStream for streaming responses');
return result;
}
async runWorkflowStream(params) {
const streamParams = {
...params,
response_mode: 'streaming'
};
const result = await this.workflow.runWorkflow(streamParams);
if (!Array.isArray(result)) throw new Error('Expected streaming response');
return async function*() {
for (const chunk of result)yield chunk;
}();
}
async getWorkflow(params) {
return this.workflow.getWorkflow(params);
}
async stopWorkflowTask(params) {
return this.workflow.stopWorkflowTask(params);
}
async getWorkflowLogs(params) {
return this.workflow.getWorkflowLogs(params);
}
async uploadFile(params) {
return this.file.uploadFile(params);
}
async audioToText(params) {
return this.file.audioToText(params);
}
async getAppParameters(params) {
return this.app.getParameters();
}
async getAppInfo(params) {
return this.app.getInfo();
}
async getAppMeta(params) {
return this.app.getMeta();
}
async sendCompletionMessage(params) {
const result = await this.app.sendCompletionMessage(params);
if (Array.isArray(result)) throw new Error('Use sendCompletionMessageStream for streaming responses');
return result;
}
async sendCompletionMessageStream(params) {
const streamParams = {
...params,
response_mode: 'streaming'
};
const result = await this.app.sendCompletionMessage(streamParams);
if (!Array.isArray(result)) throw new Error('Expected streaming response');
return async function*() {
for (const chunk of result)yield chunk;
}();
}
async stopCompletionMessage(params) {
return this.app.stopCompletionMessage(params);
}
}
const Client = DifyClient;
const MIME_MAP = {
document: {
mimeTypes: [
'text/plain',
'text/markdown',
'text/html',
'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/msword',
'text/csv',
'message/rfc822',
'application/vnd.ms-outlook',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.ms-powerpoint',
'application/xml',
'text/xml',
'application/epub+zip'
],
extensions: [
'.txt',
'.md',
'.mdx',
'.html',
'.htm',
'.pdf',
'.xlsx',
'.xls',
'.docx',
'.doc',
'.csv',
'.eml',
'.msg',
'.pptx',
'.ppt',
'.xml',
'.epub'
]
},
image: {
mimeTypes: [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'image/svg+xml'
],
extensions: [
'.jpg',
'.jpeg',
'.png',
'.gif',
'.webp',
'.svg'
]
},
audio: {
mimeTypes: [
'audio/mpeg',
'audio/mp4',
'audio/wav',
'audio/webm',
'audio/amr'
],
extensions: [
'.mp3',
'.mpga',
'.m4a',
'.wav',
'.webm',
'.amr'
]
},
video: {
mimeTypes: [
'video/mp4',
'video/quicktime',
'video/mpeg',
'audio/mpeg'
],
extensions: [
'.mp4',
'.mov',
'.mpeg',
'.mpg',
'.mpe'
]
}
};
exports.AppAPI = __webpack_exports__.AppAPI;
exports.ChatAPI = __webpack_exports__.ChatAPI;
exports.Client = __webpack_exports__.Client;
exports.ConversationAPI = __webpack_exports__.ConversationAPI;
exports.DifyClient = __webpack_exports__.DifyClient;
exports.FileAPI = __webpack_exports__.FileAPI;
exports.MIME_MAP = __webpack_exports__.MIME_MAP;
exports.WorkflowAPI = __webpack_exports__.WorkflowAPI;
exports.buildURL = __webpack_exports__.buildURL;
exports.createHeaders = __webpack_exports__.createHeaders;
exports.handleResponse = __webpack_exports__.handleResponse;
exports.handleStreamResponse = __webpack_exports__.handleStreamResponse;
exports.parseSSEChunk = __webpack_exports__.parseSSEChunk;
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
"AppAPI",
"ChatAPI",
"Client",
"ConversationAPI",
"DifyClient",
"FileAPI",
"MIME_MAP",
"WorkflowAPI",
"buildURL",
"createHeaders",
"handleResponse",
"handleStreamResponse",
"parseSSEChunk"
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
Object.defineProperty(exports, '__esModule', {
value: true
});