import { API_BASE_URL } from '~/config/api-config'; // 获取环境变量的服务端函数 const getServerEnvVar = (name: string, defaultValue: string = '') => { const value = process.env[name] || defaultValue; // console.log(`🌐 [DifyClient] 读取环境变量 ${name}:`, { // hasValue: !!process.env[name], // value: process.env[name] ? `${process.env[name].substring(0, 20)}...` : 'undefined', // usingDefault: !process.env[name] // }); return value; }; // Dify API 客户端配置 // 注意:现在通过 FastAPI 后端的 /dify 路由代理访问 Dify,使用 JWT 认证 const DIFY_CONFIG = { // API_URL 指向 FastAPI 后端的 /dify 路由 // API_BASE_URL 来自 api-config.ts,根据环境/端口自动配置 API_URL: `${API_BASE_URL}/dify`, // API_KEY 保留用于配置验证(实际不再使用,改用JWT) API_KEY: getServerEnvVar('NEXT_PUBLIC_APP_KEY', ''), APP_ID: (() => { const rawAppId = getServerEnvVar('NEXT_PUBLIC_APP_ID', ''); // 从完整URL中提取APP ID const match = rawAppId.match(/\/app\/([a-f0-9-]{36})/); return match ? match[1] : rawAppId; })(), }; console.log('🔧 Dify Client Config:', { apiUrl: DIFY_CONFIG.API_URL, apiBaseUrl: API_BASE_URL, fullDifyUrl: `${API_BASE_URL}/dify`, appId: DIFY_CONFIG.APP_ID, hasApiKey: !!DIFY_CONFIG.API_KEY, configComplete: !!(DIFY_CONFIG.API_URL && DIFY_CONFIG.APP_ID) }); // 基础请求函数 - 使用 JWT 认证通过 FastAPI 代理访问 Dify const difyFetch = async (endpoint: string, options: RequestInit = {}, jwt?: string) => { const url = `${DIFY_CONFIG.API_URL}/${endpoint.replace(/^\//, '')}`; console.log('🌐 [DifyClient] 请求FastAPI代理:', { endpoint, fullUrl: url, baseUrl: API_BASE_URL, hasJWT: !!jwt }); // 使用 JWT 认证而非 API_KEY const headers: HeadersInit = { 'Content-Type': 'application/json', ...options.headers, }; // 如果提供了 JWT,添加到请求头 if (jwt) { (headers as Record)['Authorization'] = `Bearer ${jwt}`; } else { console.warn('⚠️ [DifyClient] 没有提供 JWT,请求可能失败'); } console.log('🌐 [DifyClient] Dify API Request:', { url, method: options.method || 'GET', hasJWT: !!jwt, jwtPreview: jwt ? `${jwt.substring(0, 20)}...` : 'none' }); const response = await fetch(url, { ...options, headers, }); if (!response.ok) { const errorText = await response.text(); console.error('❌ [DifyClient] Dify API Error:', { status: response.status, statusText: response.statusText, error: errorText }); // 如果是401错误,说明JWT过期或无效 if (response.status === 401) { throw new Error('JWT认证失败,请重新登录'); } throw new Error(`Dify API Error: ${response.status} ${response.statusText}`); } return response; }; // Dify API 客户端 - 所有方法都需要传入 JWT // 注意:user 参数已移除,由后端自动从 JWT 中提取 username export const difyClient = { // 获取应用参数 async getApplicationParameters(jwt?: string) { const response = await difyFetch('parameters', { method: 'GET', }, jwt); return response.json(); }, // 获取会话列表 async getConversations(jwt?: string) { const params = new URLSearchParams({ limit: '100', first_id: '', }); const response = await difyFetch(`conversations?${params}`, { method: 'GET', }, jwt); return response.json(); }, // 获取会话消息 async getConversationMessages(conversationId: string, jwt?: string) { const params = new URLSearchParams({ conversation_id: conversationId, limit: '20', last_id: '', }); const response = await difyFetch(`messages?${params}`, { method: 'GET', }, jwt); return response.json(); }, // 发送聊天消息 async createChatMessage( inputs: Record, query: string, responseMode: string = 'streaming', conversationId?: string, files?: any[], jwt?: string ) { const body = { inputs, query, // user 字段已移除,后端会自动从 JWT 中提取 username response_mode: responseMode, conversation_id: conversationId, files: files || [], }; console.log('🌐 [DifyClient] 发送聊天消息:', { queryLength: query.length, queryPreview: query.substring(0, 100) + (query.length > 100 ? '...' : ''), responseMode, conversationId, hasInputs: !!inputs && Object.keys(inputs).length > 0, inputsKeys: inputs ? Object.keys(inputs) : [], hasFiles: !!files && files.length > 0, filesCount: files?.length || 0, hasJWT: !!jwt }); const response = await difyFetch('chat-messages', { method: 'POST', body: JSON.stringify(body), }, jwt); console.log('📡 [DifyClient] Dify API响应:', { status: response.status, statusText: response.statusText, hasBody: !!response.body, contentType: response.headers.get('Content-Type'), responseMode }); // 对于流式响应,直接返回Response对象 if (responseMode === 'streaming') { console.log('🌊 [DifyClient] 返回流式响应对象'); return response; } console.log('📄 [DifyClient] 解析JSON响应'); return response.json(); }, // 重命名会话 async renameConversation(conversationId: string, name: string, autoGenerate: boolean = false, jwt?: string) { const body = { name, auto_generate: autoGenerate, // user 字段已移除,后端会自动从 JWT 中提取 username }; const response = await difyFetch(`conversations/${conversationId}/name`, { method: 'POST', body: JSON.stringify(body), }, jwt); return response.json(); }, // 删除会话 async deleteConversation(conversationId: string, jwt?: string) { // user 字段已移除,后端会自动从 JWT 中提取 username const body = {}; console.log('🗑️ [DifyClient] 删除会话:', conversationId); try { const response = await difyFetch(`conversations/${conversationId}`, { method: 'DELETE', body: JSON.stringify(body), }, jwt); console.log('🗑️ [DifyClient] 删除会话响应:', { status: response.status, statusText: response.statusText, contentType: response.headers.get('Content-Type') }); // 检查响应的Content-Type const contentType = response.headers.get('Content-Type'); // 如果是JSON响应,解析JSON if (contentType && contentType.includes('application/json')) { const data = await response.json(); console.log('🗑️ [DifyClient] 删除会话JSON响应:', data); return data; } // 如果不是JSON,返回成功标识 const text = await response.text(); console.log('🗑️ [DifyClient] 删除会话文本响应:', text); // 返回标准成功响应 return { result: 'success' }; } catch (error: any) { console.warn('⚠️ [DifyClient] 删除会话请求失败,但可能已成功删除:', error.message); // 删除操作的特殊处理: // 即使API返回错误,实际上会话可能已经被删除 // 返回成功标识,避免误报错误 // 如果会话确实不存在,下次加载会话列表时就会发现 return { result: 'success' }; } }, // 更新消息反馈 async updateMessageFeedback(messageId: string, rating: 'like' | 'dislike' | null, jwt?: string) { const body = { rating, // user 字段已移除,后端会自动从 JWT 中提取 username }; const response = await difyFetch(`messages/${messageId}/feedbacks`, { method: 'POST', body: JSON.stringify(body), }, jwt); return response.json(); }, }; // 工具函数 export const difyUtils = { getConfig: () => DIFY_CONFIG, };