/** * Dify Chat API 模块 * * 提供客户端调用 Dify API 的函数 * 用于 Remix loader/action 中调用 Dify API * * @module api/dify/chat */ import { difyFetch } from './client.server'; // ============================================================================ // Dify Chat API 客户端 // ============================================================================ /** * Dify Chat API 客户端 * * @param jwt - JWT 认证令牌 * user 参数由后端自动从 JWT 中提取 */ export const difyClient = { /** * 获取应用参数 */ async getApplicationParameters(jwt?: string): Promise { const response = await difyFetch('parameters', { method: 'GET', }, jwt); return response.json(); }, /** * 获取会话列表 * * @param jwt - JWT 认证令牌 * @param appId - 对话应用 ID(可选,用于获取特定应用的会话列表) */ async getConversations(jwt?: string, appId?: string): Promise { const params = new URLSearchParams({ limit: '100', first_id: '', }); const response = await difyFetch(`conversations?${params}`, { method: 'GET', appId, // 传递应用 ID,会在请求头中添加 X-Dify-App-Id }, jwt); return response.json(); }, /** * 获取会话消息 */ async getConversationMessages(conversationId: string, jwt?: string): Promise { const params = new URLSearchParams({ conversation_id: conversationId, limit: '20', last_id: '', }); const response = await difyFetch(`messages?${params}`, { method: 'GET', }, jwt); return response.json(); }, /** * 发送聊天消息 * * @param inputs - 输入参数 * @param query - 用户问题 * @param responseMode - 响应模式 ('streaming' | 'blocking') * @param conversationId - 会话 ID * @param files - 附件文件 * @param jwt - JWT 认证令牌 * @param appId - 对话应用 ID(可选,用于切换不同的 Dify 应用) * @returns 对于流式响应返回 Response 对象,否则返回 JSON */ async createChatMessage( inputs: Record, query: string, responseMode: string = 'streaming', conversationId?: string, files?: any[], jwt?: string, appId?: string ): Promise { const body = { inputs, query, response_mode: responseMode, conversation_id: conversationId, files: files || [], }; const response = await difyFetch('chat-messages', { method: 'POST', body: JSON.stringify(body), appId, // 传递应用 ID,会在请求头中添加 X-Dify-App-Id }, jwt); // 对于流式响应,直接返回 Response 对象 if (responseMode === 'streaming') { return response; } console.log('[Dify Chat] 解析 JSON 响应'); return response.json(); }, /** * 重命名会话 */ async renameConversation( conversationId: string, name: string, autoGenerate: boolean = false, jwt?: string ): Promise { const body = { name, auto_generate: autoGenerate, }; const response = await difyFetch(`conversations/${conversationId}/name`, { method: 'POST', body: JSON.stringify(body), }, jwt); return response.json(); }, /** * 删除会话 */ async deleteConversation(conversationId: string, jwt?: string): Promise { console.log('[Dify Chat] 删除会话:', conversationId); try { const response = await difyFetch(`conversations/${conversationId}`, { method: 'DELETE', body: JSON.stringify({}), }, jwt); // 对于 204 No Content 响应,直接返回成功 if (response.status === 204) { console.log('[Dify Chat] 删除会话成功:', conversationId); return { result: 'success' }; } const contentType = response.headers.get('Content-Type'); if (contentType && contentType.includes('application/json')) { const data = await response.json(); return data; } const text = await response.text(); console.log('[Dify Chat] 删除会话文本响应:', text); return { result: 'success' }; } catch (error: any) { // 权限不足等明确错误需要抛出,不能吞掉 if (error.message?.includes('403') || error.message?.includes('401')) { throw error; } // 网络超时等不确定错误才降级为成功(Dify 可能已执行删除) console.warn('[Dify Chat] 删除会话请求失败,但可能已成功删除:', error.message); return { result: 'success' }; } }, /** * 更新消息反馈 */ async updateMessageFeedback( messageId: string, rating: 'like' | 'dislike' | null, jwt?: string ): Promise { const body = { rating, }; const response = await difyFetch(`messages/${messageId}/feedbacks`, { method: 'POST', body: JSON.stringify(body), }, jwt); return response.json(); }, };