增加get_decrypted_password函数

This commit is contained in:
jingrow 2026-03-16 04:44:24 +08:00
parent a392f71dd7
commit f3175d822e
3 changed files with 45 additions and 82 deletions

View File

@ -24,14 +24,7 @@ export class FlowExecutor {
* @returns {Promise<Object>} 执行结果 * @returns {Promise<Object>} 执行结果
*/ */
async executeFlow(nodes, edges, initialData = {}) { 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) { if (this.isExecuting) {
console.error('[FlowExecutor] Flow already executing');
console.groupEnd();
throw new Error('流程正在执行中,请等待完成'); throw new Error('流程正在执行中,请等待完成');
} }
@ -44,20 +37,12 @@ export class FlowExecutor {
const executionNodes = JSON.parse(JSON.stringify(nodes)); const executionNodes = JSON.parse(JSON.stringify(nodes));
const executionEdges = JSON.parse(JSON.stringify(edges)); 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); this.buildExecutionGraph(executionNodes, executionEdges);
console.log('Execution order:', this.executionOrder);
// 执行流程 // 执行流程
const result = await this.executeGraph(); const result = await this.executeGraph();
console.log('[FlowExecutor] executeFlow SUCCESS');
console.log('Final results:', result);
console.groupEnd();
return { return {
success: true, success: true,
result: result, result: result,
@ -65,9 +50,6 @@ export class FlowExecutor {
context: this.executionContext context: this.executionContext
}; };
} catch (error) { } catch (error) {
console.error('[FlowExecutor] executeFlow FAILED:', error);
console.error('Error stack:', error.stack);
console.groupEnd();
return { return {
success: false, success: false,
error: error.message, error: error.message,
@ -190,9 +172,6 @@ export class FlowExecutor {
* @returns {Promise<Object>} 执行结果 * @returns {Promise<Object>} 执行结果
*/ */
async executeGraph() { async executeGraph() {
console.log('[FlowExecutor] executeGraph START');
console.log('Execution order:', this.executionOrder);
const context = { const context = {
node_results: {}, node_results: {},
flow_id: this.executionContext.agent_name flow_id: this.executionContext.agent_name
@ -204,19 +183,14 @@ export class FlowExecutor {
// 按拓扑排序执行节点 // 按拓扑排序执行节点
for (const nodeId of this.executionOrder) { for (const nodeId of this.executionOrder) {
const node = this.nodes.get(nodeId); const node = this.nodes.get(nodeId);
console.log(`[FlowExecutor] Processing node: ${nodeId} (${node?.type})`);
// 检查节点是否应该被执行O(1)时间复杂度) // 检查节点是否应该被执行O(1)时间复杂度)
if (!this.shouldExecuteNode(node, context, executedNodes)) { if (!this.shouldExecuteNode(node, context, executedNodes)) {
console.log(`[FlowExecutor] Skipping node ${nodeId} (shouldExecuteNode=false)`);
continue; continue;
} }
console.log(`[FlowExecutor] Executing node ${nodeId}...`);
// 执行节点 // 执行节点
const result = await this.executeNode(node, context); const result = await this.executeNode(node, context);
console.log(`[FlowExecutor] Node ${nodeId} result:`, result);
results[nodeId] = result; results[nodeId] = result;
context.node_results[nodeId] = result; context.node_results[nodeId] = result;
executedNodes.add(nodeId); executedNodes.add(nodeId);
@ -225,7 +199,6 @@ export class FlowExecutor {
this.recordExecutionHistory(node, result); this.recordExecutionHistory(node, result);
} }
console.log('[FlowExecutor] executeGraph COMPLETE, results:', results);
return results; return results;
} }
@ -294,44 +267,23 @@ export class FlowExecutor {
edges: this.edges 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`, { const response = await fetch(`/jingrow/nodes/${node.type}/execute`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Jingrow-CSRF-Token': window.jingrow?.csrf_token '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(); const resJson = await response.json();
console.log('Response JSON:', resJson);
console.groupEnd();
if (!resJson.message || resJson.message.success === false) { if (!resJson.message || resJson.message.success === false) {
const errorMsg = resJson.message?.error || resJson.error || '节点执行失败'; throw new Error(resJson.message?.error || '节点执行失败');
console.error('[FlowExecutor] Node execution failed:', errorMsg);
console.error('[FlowExecutor] Full response:', resJson);
throw new Error(errorMsg);
} }
// 更新节点状态 // 更新节点状态
@ -342,9 +294,6 @@ export class FlowExecutor {
return resJson.message; return resJson.message;
} catch (error) { } catch (error) {
console.groupEnd();
console.error('[FlowExecutor] Node execution error:', error);
console.error('[FlowExecutor] Error stack:', error.stack);
// 处理执行失败 // 处理执行失败
node.status = 'failed'; node.status = 'failed';
node.error = error.message; node.error = error.message;

View File

@ -4,20 +4,9 @@ Jingrow Cloud API 调用工具
""" """
import requests import requests
from functools import lru_cache import jingrow
from jingrow.utils.auth import get_jingrow_cloud_api_headers, get_jingrow_cloud_api_url from jingrow.utils.auth import get_jingrow_cloud_api_headers, get_jingrow_cloud_api_url
from jingrow.utils.password import get_decrypted_password
@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()
def call_jingrow_model(prompt: str, def call_jingrow_model(prompt: str,
@ -98,10 +87,9 @@ def call_chatgpt_model(prompt: str,
model: str = None): model: str = None):
"""调用 ChatGPT 模型""" """调用 ChatGPT 模型"""
try: try:
ai_settings = _get_cached_ai_settings() api_url = jingrow.get_single_value("Ai Settings", "chatgpt_api_url") or "https://api.openai.com/v1/chat/completions"
api_url = ai_settings.get('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)
api_key = ai_settings.get('chatgpt_api_key') model_name = model or jingrow.get_single_value("Ai Settings", "chatgpt_api_model") or "gpt-4o"
model_name = model or ai_settings.get('chatgpt_api_model') or "gpt-4o"
if not api_key: if not api_key:
return {"success": False, "error": "ChatGPT API 未配置,请在 Ai Settings 中设置 chatgpt_api_key"} return {"success": False, "error": "ChatGPT API 未配置,请在 Ai Settings 中设置 chatgpt_api_key"}
content = [{"type": "text", "text": prompt}] content = [{"type": "text", "text": prompt}]
@ -145,10 +133,9 @@ def call_deepseek_model(prompt: str,
model: str = None): model: str = None):
"""调用 DeepSeek 模型""" """调用 DeepSeek 模型"""
try: try:
ai_settings = _get_cached_ai_settings() api_url = jingrow.get_single_value("Ai Settings", "deepseek_api_url")
api_url = ai_settings.get('deepseek_api_url') api_key = get_decrypted_password("Ai Settings", "Ai Settings", "deepseek_api_key", raise_exception=False)
api_key = ai_settings.get('deepseek_api_key') model_name = model or jingrow.get_single_value("Ai Settings", "deepseek_api_model") or "deepseek-chat"
model_name = model or ai_settings.get('deepseek_api_model') or "deepseek-chat"
if not api_url or not api_key: if not api_url or not api_key:
return {"success": False, "error": "DeepSeek API 未配置,请在 Ai Settings 中设置 deepseek_api_url 和 deepseek_api_key"} return {"success": False, "error": "DeepSeek API 未配置,请在 Ai Settings 中设置 deepseek_api_url 和 deepseek_api_key"}
content = [{"type": "text", "text": prompt}] content = [{"type": "text", "text": prompt}]
@ -192,10 +179,9 @@ def call_doubao_model(prompt: str,
model: str = None): model: str = None):
"""调用豆包模型""" """调用豆包模型"""
try: try:
ai_settings = _get_cached_ai_settings() api_url = jingrow.get_single_value("Ai Settings", "doubao_api_url")
api_url = ai_settings.get('doubao_api_url') api_key = get_decrypted_password("Ai Settings", "Ai Settings", "doubao_api_key", raise_exception=False)
api_key = ai_settings.get('doubao_api_key') model_name = model or jingrow.get_single_value("Ai Settings", "doubao_api_model") or "doubao-pro-32k-241215"
model_name = model or ai_settings.get('doubao_api_model') or "doubao-pro-32k-241215"
if not api_url or not api_key: if not api_url or not api_key:
return {"success": False, "error": "豆包 API 未配置,请在 Ai Settings 中设置 doubao_api_url 和 doubao_api_key"} return {"success": False, "error": "豆包 API 未配置,请在 Ai Settings 中设置 doubao_api_url 和 doubao_api_key"}
content = [{"type": "text", "text": prompt}] content = [{"type": "text", "text": prompt}]

View File

@ -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}")