增加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>} 执行结果
*/
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<Object>} 执行结果
*/
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;

View File

@ -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}]

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