增加get_decrypted_password函数
This commit is contained in:
parent
a392f71dd7
commit
f3175d822e
@ -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;
|
||||
|
||||
@ -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}]
|
||||
|
||||
28
apps/jingrow/jingrow/utils/password.py
Normal file
28
apps/jingrow/jingrow/utils/password.py
Normal 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}")
|
||||
Loading…
x
Reference in New Issue
Block a user