UNPKG

dify-node-sdk

Version:
542 lines (532 loc) 11.7 kB
import axios from "axios"; //#region src/utils/streamResponse/handler/base.ts /** * 基础流处理器 - 提供通用的流处理机制 */ var BaseStreamHandler = class { eventHandlers = new Map(); errorHandlers = []; completionHandlers = []; stream; isStopped = false; isStart = false; /** * 创建流处理器 * @param stream 响应流对象 */ constructor(stream) { this.stream = stream; } start() { if (this.isStart) return; this.isStart = true; this.processStream(); } /** * 处理流内容 */ processStream() { let buffer = ""; this.stream.on("data", (chunk) => { if (this.isStopped) return; const str = chunk.toString(); buffer += str; if (buffer.includes("\n\n")) { const parts = buffer.split("\n\n"); buffer = parts.pop() || ""; for (const part of parts) if (part.startsWith("data: ")) { const data = part.slice(6); this.processData(data); } } }); this.stream.on("error", (err) => { this.emitError(err); }); this.stream.on("end", () => { if (buffer && buffer.startsWith("data: ")) { const data = buffer.slice(6); this.processData(data); } if (!this.isStopped) { this.emitCompletion(); this.cleanUp(); } }); } /** * 处理单条数据 * @param data 数据字符串 */ /** * 处理接收到的数据 */ processData(data) { if (data === "ping" || data === "data: ping") return; try { const parsed = JSON.parse(data); this.dispatchEvent(parsed); } catch (e) { console.warn("解析数据失败:", e); } } /** * 分发事件 * @param event 事件对象 */ dispatchEvent(event) { const eventType = event.event; if (eventType) { const handlers = this.eventHandlers.get(eventType); if (handlers && handlers.length > 0) handlers.forEach((handler) => handler(event)); } } /** * 触发错误 * @param error 错误对象 */ emitError(error) { this.errorHandlers.forEach((handler) => handler(error)); } /** * 触发完成 */ emitCompletion() { this.completionHandlers.forEach((handler) => handler()); } /** * 清理资源 */ cleanUp() { this.isStopped = true; } /** * 注册事件处理器 * @param eventType 事件类型 * @param handler 处理函数 */ registerEventHandler(eventType, handler) { if (!this.eventHandlers.has(eventType)) this.eventHandlers.set(eventType, []); this.eventHandlers.get(eventType).push(handler); } /** * 注册错误处理器 * @param handler 错误处理函数 */ onError(handler) { this.errorHandlers.push(handler); return this; } /** * 注册完成处理器 * @param handler 完成处理函数 */ onFinished(handler) { this.completionHandlers.push(handler); return this; } /** * 等待流完成 * @returns Promise 当流完成时解析 */ async waitForCompletion() { return new Promise((resolve, reject) => { this.onFinished(() => resolve()); this.onError((error) => reject(error)); }); } }; //#endregion //#region src/utils/streamResponse/handler/chat.ts /** * 聊天流处理器 */ var ChatStreamHandler = class extends BaseStreamHandler { /** * 注册消息事件处理器 */ onMessage(handler) { this.registerEventHandler("message", handler); return this; } /** * 注册消息文件事件处理器 */ onMessageFile(handler) { this.registerEventHandler("message_file", handler); return this; } /** * 注册消息结束事件处理器 */ onMessageEnd(handler) { this.registerEventHandler("message_end", handler); return this; } /** * 注册文本转语音消息事件处理器 */ onTtsMessage(handler) { this.registerEventHandler("tts_message", handler); return this; } /** * 注册文本转语音结束事件处理器 */ onTtsMessageEnd(handler) { this.registerEventHandler("tts_message_end", handler); return this; } /** * 注册消息替换事件处理器 */ onMessageReplace(handler) { this.registerEventHandler("message_replace", handler); return this; } /** * 注册错误事件处理器 */ onErrorEvent(handler) { this.registerEventHandler("error", handler); return this; } }; //#endregion //#region src/utils/streamResponse/handler/completion.ts /** * 完成流处理器 */ var CompletionStreamHandler = class extends BaseStreamHandler { /** * 注册消息事件处理器 */ onMessage(handler) { this.registerEventHandler("message", handler); return this; } /** * 注册消息结束事件处理器 */ onMessageEnd(handler) { this.registerEventHandler("message_end", handler); return this; } /** * 注册文本转语音消息事件处理器 */ onTtsMessage(handler) { this.registerEventHandler("tts_message", handler); return this; } /** * 注册文本转语音结束事件处理器 */ onTtsMessageEnd(handler) { this.registerEventHandler("tts_message_end", handler); return this; } /** * 注册消息替换事件处理器 */ onMessageReplace(handler) { this.registerEventHandler("message_replace", handler); return this; } /** * 注册错误事件处理器 */ onErrorEvent(handler) { this.registerEventHandler("error", handler); return this; } }; //#endregion //#region src/utils/streamResponse/handler/workflow.ts /** * 工作流流处理器 */ var WorkflowStreamHandler = class extends BaseStreamHandler { /** * 注册工作流开始事件处理器 */ onWorkflowStarted(handler) { this.registerEventHandler("workflow_started", handler); return this; } /** * 注册工作流完成事件处理器 */ onWorkflowFinished(handler) { this.registerEventHandler("workflow_finished", handler); return this; } /** * 注册节点开始事件处理器 */ onNodeStarted(handler) { this.registerEventHandler("node_started", handler); return this; } /** * 注册节点完成事件处理器 */ onNodeFinished(handler) { this.registerEventHandler("node_finished", handler); return this; } /** * 注册文本块事件处理器 */ onTextChunk(handler) { this.registerEventHandler("text_chunk", handler); return this; } /** * 注册文本转语音消息事件处理器 */ onTtsMessage(handler) { this.registerEventHandler("tts_message", handler); return this; } /** * 注册文本转语音结束事件处理器 */ onTtsMessageEnd(handler) { this.registerEventHandler("tts_message_end", handler); return this; } }; //#endregion //#region src/utils/request.ts const createAxiosInstance = (apiKey, baseUrl) => { const axiosInstance = axios.create({ baseURL: baseUrl, headers: { "Content-Type": "application/json" }, timeout: 5e4 }); axiosInstance.interceptors.request.use((config) => { config.headers.Authorization = `Bearer ${apiKey}`; return config; }); return axiosInstance; }; //#endregion //#region src/client/dify.ts /** * Dify API Base Class */ var DifyClient = class { apiKey; baseUrl; request; /** * Create Dify Client Instance * @param apiKey API Key * @param baseUrl API Base URL, default to official API address */ constructor(apiKey, baseUrl = "https://api.dify.ai/v1") { this.apiKey = apiKey; this.baseUrl = baseUrl; this.request = createAxiosInstance(apiKey, baseUrl); } messageFeedback(messageId, rating, user) { return this.request({ method: "POST", url: `/messages/${messageId}/feedbacks`, data: { rating, user } }); } getApplicationParameters() { return this.request({ method: "GET", url: "/parameters" }); } getMeta() { return this.request({ method: "GET", url: "/meta" }); } fileUpload(file, user) { const formData = new FormData(); formData.append("file", file); formData.append("user", user); return this.request({ method: "POST", url: "/files/upload", data: formData, headers: { "Content-Type": "multipart/form-data" } }); } /** * @deprecated dify 源码中还接受了voice参数,同时源码中貌似并未对streaming参数进行处理 */ textToVideo(data) { return this.request({ method: "POST", url: "/text-to-audio", data, responseType: data.streaming ? "stream" : "json" }); } }; //#endregion //#region src/client/chat.ts var ChatClient = class extends DifyClient { async createChatMessage(params) { const defaultParams = { response_mode: "blocking", inputs: {} }; const mergeParams = { ...defaultParams, ...params }; const response = await this.request({ method: "POST", url: "/chat-messages", data: mergeParams, responseType: mergeParams.response_mode === "streaming" ? "stream" : "json" }); if (mergeParams.response_mode === "streaming") return new ChatStreamHandler(response.data); return response.data; } getSuggested(messageId, user) { return this.request({ method: "GET", url: `/messages/${messageId}/suggested`, params: { user } }); } /** * @param taskId get it from chunk response * @param user */ stopMessage(taskId, user) { return this.request({ method: "POST", url: `/chat-messages/${taskId}/stop`, data: { user } }); } getConversations(params) { return this.request({ method: "GET", url: "/conversations", params }); } getConversationMessages(params) { return this.request({ method: "GET", url: `/messages`, params }); } renameConversation(data) { const { conversation_id,...rest } = data; return this.request({ method: "POST", url: `/conversations/${conversation_id}/name`, data: rest }); } deleteConversation(data) { const { conversation_id,...rest } = data; return this.request({ method: "DELETE", url: `/conversations/${conversation_id}`, data: rest }); } /** * @param file file support ["mp3", "m4a", "wav", "webm", "amr"], limit 15MB * @param user 用户 */ audioToText(file, user) { const formData = new FormData(); formData.append("file", file); formData.append("user", user); return this.request({ method: "POST", url: "/audio-to-text", data: formData, headers: { "Content-Type": "multipart/form-data" } }); } }; //#endregion //#region src/client/workflow.ts var WorkflowClient = class extends DifyClient { async run(data) { const defaultParams = { response_mode: "blocking", inputs: {} }; const mergeParams = { ...defaultParams, ...data }; const response = await this.request({ method: "POST", url: "/workflows/run", data: mergeParams, responseType: mergeParams.response_mode === "streaming" ? "stream" : "json" }); if (mergeParams.response_mode === "streaming") return new WorkflowStreamHandler(response.data); return response.data; } getRunDetail(workflowRunId) { return this.request({ method: "GET", url: `/workflows/runs/${workflowRunId}` }); } stop(taskId, user) { return this.request({ method: "POST", url: `/workflows/tasks/${taskId}/stop`, data: { user } }); } getLogs(params) { return this.request({ method: "GET", url: `/workflows/logs`, params }); } }; //#endregion //#region src/client/completion.ts var CompletionClient = class extends DifyClient { async createCompletionMessage(data) { const defaultParams = { response_mode: "blocking" }; const mergeParams = { ...defaultParams, ...data }; const response = await this.request({ method: "POST", url: "/completion-messages", data: mergeParams, responseType: mergeParams.response_mode === "streaming" ? "stream" : "json" }); if (mergeParams.response_mode === "streaming") return new CompletionStreamHandler(response.data); return response.data; } stop(taskId, user) { return this.request({ method: "POST", url: `/completion-messages/${taskId}/stop`, data: { user } }); } }; //#endregion export { ChatClient, CompletionClient, DifyClient, WorkflowClient };