diff --git a/apps/jingrow/frontend/src/core/features/flows/executors/flowExecutor.js b/apps/jingrow/frontend/src/core/features/flows/executors/flowExecutor.js index dbbef7c..d1e5ab2 100644 --- a/apps/jingrow/frontend/src/core/features/flows/executors/flowExecutor.js +++ b/apps/jingrow/frontend/src/core/features/flows/executors/flowExecutor.js @@ -24,14 +24,7 @@ export class FlowExecutor { * @returns {Promise} 执行结果 */ async executeFlow(nodes, edges, initialData = {}) { - console.group('[FlowExecutor] executeFlow START'); - console.log('Nodes count:', nodes?.length); - console.log('Edges count:', edges?.length); - console.log('Initial data:', initialData); - if (this.isExecuting) { - console.error('[FlowExecutor] Flow already executing'); - console.groupEnd(); throw new Error('流程正在执行中,请等待完成'); } @@ -44,20 +37,12 @@ export class FlowExecutor { const executionNodes = JSON.parse(JSON.stringify(nodes)); const executionEdges = JSON.parse(JSON.stringify(edges)); - console.log('Execution nodes:', executionNodes.map(n => ({ id: n.id, type: n.type }))); - console.log('Execution edges:', executionEdges); - // 预构建执行图(一次性构建,避免重复计算) this.buildExecutionGraph(executionNodes, executionEdges); - console.log('Execution order:', this.executionOrder); // 执行流程 const result = await this.executeGraph(); - console.log('[FlowExecutor] executeFlow SUCCESS'); - console.log('Final results:', result); - console.groupEnd(); - return { success: true, result: result, @@ -65,9 +50,6 @@ export class FlowExecutor { context: this.executionContext }; } catch (error) { - console.error('[FlowExecutor] executeFlow FAILED:', error); - console.error('Error stack:', error.stack); - console.groupEnd(); return { success: false, error: error.message, @@ -190,9 +172,6 @@ export class FlowExecutor { * @returns {Promise} 执行结果 */ async executeGraph() { - console.log('[FlowExecutor] executeGraph START'); - console.log('Execution order:', this.executionOrder); - const context = { node_results: {}, flow_id: this.executionContext.agent_name @@ -204,19 +183,14 @@ export class FlowExecutor { // 按拓扑排序执行节点 for (const nodeId of this.executionOrder) { const node = this.nodes.get(nodeId); - console.log(`[FlowExecutor] Processing node: ${nodeId} (${node?.type})`); // 检查节点是否应该被执行(O(1)时间复杂度) if (!this.shouldExecuteNode(node, context, executedNodes)) { - console.log(`[FlowExecutor] Skipping node ${nodeId} (shouldExecuteNode=false)`); continue; } - console.log(`[FlowExecutor] Executing node ${nodeId}...`); // 执行节点 const result = await this.executeNode(node, context); - console.log(`[FlowExecutor] Node ${nodeId} result:`, result); - results[nodeId] = result; context.node_results[nodeId] = result; executedNodes.add(nodeId); @@ -225,7 +199,6 @@ export class FlowExecutor { this.recordExecutionHistory(node, result); } - console.log('[FlowExecutor] executeGraph COMPLETE, results:', results); return results; } @@ -294,44 +267,23 @@ export class FlowExecutor { edges: this.edges }; - // Debug: log request details - console.group(`[FlowExecutor] Executing node: ${node.type} (${node.id})`); - console.log('Node data:', JSON.parse(JSON.stringify(node))); - console.log('Node inputs:', nodeInputs); - console.log('Node config:', config); - console.log('Context:', JSON.parse(JSON.stringify(context))); - console.log('Request URL:', `/jingrow/nodes/${node.type}/execute`); - console.log('CSRF Token:', window.jingrow?.csrf_token); - - const requestBody = JSON.stringify({ - context, - inputs: nodeInputs, - config - }); - console.log('Request body size:', requestBody.length, 'bytes'); - const response = await fetch(`/jingrow/nodes/${node.type}/execute`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Jingrow-CSRF-Token': window.jingrow?.csrf_token }, - body: requestBody + body: JSON.stringify({ + context, + inputs: nodeInputs, + config + }) }); - // Debug: log response details - console.log('Response status:', response.status, response.statusText); - console.log('Response headers:', Object.fromEntries(response.headers.entries())); - const resJson = await response.json(); - console.log('Response JSON:', resJson); - console.groupEnd(); if (!resJson.message || resJson.message.success === false) { - const errorMsg = resJson.message?.error || resJson.error || '节点执行失败'; - console.error('[FlowExecutor] Node execution failed:', errorMsg); - console.error('[FlowExecutor] Full response:', resJson); - throw new Error(errorMsg); + throw new Error(resJson.message?.error || '节点执行失败'); } // 更新节点状态 @@ -342,9 +294,6 @@ export class FlowExecutor { return resJson.message; } catch (error) { - console.groupEnd(); - console.error('[FlowExecutor] Node execution error:', error); - console.error('[FlowExecutor] Error stack:', error.stack); // 处理执行失败 node.status = 'failed'; node.error = error.message; diff --git a/apps/jingrow/jingrow/utils/jingrow_cloud.py b/apps/jingrow/jingrow/utils/jingrow_cloud.py index f048d7b..10af016 100644 --- a/apps/jingrow/jingrow/utils/jingrow_cloud.py +++ b/apps/jingrow/jingrow/utils/jingrow_cloud.py @@ -4,20 +4,9 @@ Jingrow Cloud API 调用工具 """ import requests -from functools import lru_cache +import jingrow from jingrow.utils.auth import get_jingrow_cloud_api_headers, get_jingrow_cloud_api_url - - -@lru_cache(maxsize=1) -def _get_cached_ai_settings(): - """缓存 AI Settings 配置(含密码字段解密),避免重复请求""" - from jingrow.utils.jingrow_api import get_ai_settings_from_jingrow - return get_ai_settings_from_jingrow() or {} - - -def clear_ai_settings_cache(): - """清除 AI Settings 缓存,配置更新后调用""" - _get_cached_ai_settings.cache_clear() +from jingrow.utils.password import get_decrypted_password def call_jingrow_model(prompt: str, @@ -98,10 +87,9 @@ def call_chatgpt_model(prompt: str, model: str = None): """调用 ChatGPT 模型""" try: - ai_settings = _get_cached_ai_settings() - api_url = ai_settings.get('chatgpt_api_url') or "https://api.openai.com/v1/chat/completions" - api_key = ai_settings.get('chatgpt_api_key') - model_name = model or ai_settings.get('chatgpt_api_model') or "gpt-4o" + api_url = jingrow.get_single_value("Ai Settings", "chatgpt_api_url") or "https://api.openai.com/v1/chat/completions" + api_key = get_decrypted_password("Ai Settings", "Ai Settings", "chatgpt_api_key", raise_exception=False) + model_name = model or jingrow.get_single_value("Ai Settings", "chatgpt_api_model") or "gpt-4o" if not api_key: return {"success": False, "error": "ChatGPT API 未配置,请在 Ai Settings 中设置 chatgpt_api_key"} content = [{"type": "text", "text": prompt}] @@ -145,10 +133,9 @@ def call_deepseek_model(prompt: str, model: str = None): """调用 DeepSeek 模型""" try: - ai_settings = _get_cached_ai_settings() - api_url = ai_settings.get('deepseek_api_url') - api_key = ai_settings.get('deepseek_api_key') - model_name = model or ai_settings.get('deepseek_api_model') or "deepseek-chat" + api_url = jingrow.get_single_value("Ai Settings", "deepseek_api_url") + api_key = get_decrypted_password("Ai Settings", "Ai Settings", "deepseek_api_key", raise_exception=False) + model_name = model or jingrow.get_single_value("Ai Settings", "deepseek_api_model") or "deepseek-chat" if not api_url or not api_key: return {"success": False, "error": "DeepSeek API 未配置,请在 Ai Settings 中设置 deepseek_api_url 和 deepseek_api_key"} content = [{"type": "text", "text": prompt}] @@ -192,10 +179,9 @@ def call_doubao_model(prompt: str, model: str = None): """调用豆包模型""" try: - ai_settings = _get_cached_ai_settings() - api_url = ai_settings.get('doubao_api_url') - api_key = ai_settings.get('doubao_api_key') - model_name = model or ai_settings.get('doubao_api_model') or "doubao-pro-32k-241215" + api_url = jingrow.get_single_value("Ai Settings", "doubao_api_url") + api_key = get_decrypted_password("Ai Settings", "Ai Settings", "doubao_api_key", raise_exception=False) + model_name = model or jingrow.get_single_value("Ai Settings", "doubao_api_model") or "doubao-pro-32k-241215" if not api_url or not api_key: return {"success": False, "error": "豆包 API 未配置,请在 Ai Settings 中设置 doubao_api_url 和 doubao_api_key"} content = [{"type": "text", "text": prompt}] diff --git a/apps/jingrow/jingrow/utils/password.py b/apps/jingrow/jingrow/utils/password.py new file mode 100644 index 0000000..57710f5 --- /dev/null +++ b/apps/jingrow/jingrow/utils/password.py @@ -0,0 +1,28 @@ +"""Password utilities for jlocal environment.""" + +import requests +from jingrow.config import Config +from jingrow.utils.auth import get_jingrow_api_headers + + +def get_decrypted_password(pagetype, name, fieldname="password", raise_exception=True): + """Get decrypted password from remote Jingrow SaaS API.""" + headers = get_jingrow_api_headers() + if not headers: + if raise_exception: + raise Exception("JINGROW_API_KEY or JINGROW_API_SECRET not configured") + return None + + resp = requests.post( + f"{Config.jingrow_server_url}/api/action/jingrow.client.get_password", + headers=headers, + json={"pagetype": pagetype, "name": name, "fieldname": fieldname}, + timeout=10 + ) + + if resp.status_code == 200: + result = resp.json() + return result.get("message") if isinstance(result, dict) else result + + if raise_exception: + raise Exception(f"Password not found for {pagetype} {name} {fieldname}")