Files
leaudit-platform-frontend/app/api/dify-chat/chat.ts
T
PingChuan 5bee9288b9 feat:替换 Dify 为自建 RAG去实现
1、修复了若干无权限时的失败提示语
2、新增了一个生成后续建议问题的功能
3、重构了知识问答部分的权限管理模块
4、修复了若干渲染不恰当的样式渲染
2026-04-10 16:20:32 +08:00

191 lines
5.5 KiB
TypeScript

/**
* 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<any> {
const response = await difyFetch('parameters', {
method: 'GET',
}, jwt);
return response.json();
},
/**
* 获取会话列表
*
* @param jwt - JWT 认证令牌
* @param appId - 对话应用 ID(可选,用于获取特定应用的会话列表)
*/
async getConversations(jwt?: string, appId?: string): Promise<any> {
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<any> {
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<string, any>,
query: string,
responseMode: string = 'streaming',
conversationId?: string,
files?: any[],
jwt?: string,
appId?: string
): Promise<Response | any> {
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<any> {
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<any> {
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<any> {
const body = {
rating,
};
const response = await difyFetch(`messages/${messageId}/feedbacks`, {
method: 'POST',
body: JSON.stringify(body),
}, jwt);
return response.json();
},
};