Workflow Analysen V1.1 #73
|
|
@ -31,6 +31,42 @@ OPENROUTER_MODEL = os.getenv("OPENROUTER_MODEL", "anthropic/claude-sonnet-4")
|
|||
|
||||
router = APIRouter(prefix="/api/prompts", tags=["prompts"])
|
||||
|
||||
# Metadaten-Schlüssel in workflow aggregate_results (nicht als „einziger“ Nutzer-Output)
|
||||
_WORKFLOW_AGG_META_KEYS = frozenset({
|
||||
"combined_analysis",
|
||||
"all_signals",
|
||||
"total_nodes",
|
||||
"executed_nodes",
|
||||
"failed_nodes",
|
||||
"skipped_nodes",
|
||||
})
|
||||
|
||||
|
||||
def _workflow_user_facing_content(agg: object) -> str:
|
||||
"""
|
||||
Nutzer-sichtbarer Text wie im Admin WorkflowResultViewer („Final Output“):
|
||||
primär aggregated_result['analysis_core'], nicht das gesamte JSON.
|
||||
"""
|
||||
if agg is None:
|
||||
return ""
|
||||
if isinstance(agg, str):
|
||||
return agg
|
||||
if not isinstance(agg, dict):
|
||||
return json.dumps(agg, ensure_ascii=False)
|
||||
core = agg.get("analysis_core")
|
||||
if isinstance(core, str) and core.strip():
|
||||
return core
|
||||
combined = agg.get("combined_analysis")
|
||||
if isinstance(combined, str) and combined.strip():
|
||||
return combined
|
||||
non_meta = [k for k in agg.keys() if k not in _WORKFLOW_AGG_META_KEYS]
|
||||
if len(non_meta) == 1:
|
||||
v = agg[non_meta[0]]
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
return json.dumps(v, ensure_ascii=False)
|
||||
return json.dumps(agg, ensure_ascii=False)
|
||||
|
||||
|
||||
@router.get("")
|
||||
def list_prompts(session: dict=Depends(require_auth)):
|
||||
|
|
@ -1254,17 +1290,7 @@ async def execute_unified_prompt(
|
|||
else:
|
||||
content = json.dumps(final_output, ensure_ascii=False)
|
||||
elif result['type'] == 'workflow':
|
||||
# Graph-Workflows: kein "output", sondern aggregated_result
|
||||
agg = result.get('aggregated_result')
|
||||
if isinstance(agg, dict) and len(agg) == 1:
|
||||
v = list(agg.values())[0]
|
||||
content = v if isinstance(v, str) else json.dumps(v, ensure_ascii=False)
|
||||
elif agg is None:
|
||||
content = ''
|
||||
elif isinstance(agg, str):
|
||||
content = agg
|
||||
else:
|
||||
content = json.dumps(agg, ensure_ascii=False)
|
||||
content = _workflow_user_facing_content(result.get('aggregated_result'))
|
||||
else:
|
||||
# For base prompts, use output directly
|
||||
content = result.get('output', '')
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { useState, useEffect, useMemo } from 'react'
|
|||
import { Brain, Trash2, ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { api } from '../utils/api'
|
||||
import { getWorkflowDisplayContent } from '../utils/workflowDisplay'
|
||||
import { useAuth } from '../context/AuthContext'
|
||||
import Markdown from '../utils/Markdown'
|
||||
import UsageBadge from '../components/UsageBadge'
|
||||
|
|
@ -400,15 +401,7 @@ export default function Analysis() {
|
|||
content = JSON.stringify(finalOutput, null, 2)
|
||||
}
|
||||
} else if (result.type === 'workflow') {
|
||||
const agg = result.aggregated_result
|
||||
if (agg != null && typeof agg === 'object' && !Array.isArray(agg) && Object.keys(agg).length === 1) {
|
||||
const v = Object.values(agg)[0]
|
||||
content = typeof v === 'string' ? v : JSON.stringify(v, null, 2)
|
||||
} else if (typeof agg === 'string') {
|
||||
content = agg
|
||||
} else {
|
||||
content = JSON.stringify(agg ?? {}, null, 2)
|
||||
}
|
||||
content = getWorkflowDisplayContent(result.aggregated_result)
|
||||
} else {
|
||||
// For base prompts, use output directly
|
||||
content = typeof result.output === 'string' ? result.output : JSON.stringify(result.output, null, 2)
|
||||
|
|
|
|||
37
frontend/src/utils/workflowDisplay.js
Normal file
37
frontend/src/utils/workflowDisplay.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Nutzer-sichtbare Textausgabe eines Workflow-Laufs – gleiche Logik wie
|
||||
* WorkflowResultViewer („Final Output“): primär aggregated_result.analysis_core.
|
||||
*/
|
||||
const AGG_META_KEYS = new Set([
|
||||
'combined_analysis',
|
||||
'all_signals',
|
||||
'total_nodes',
|
||||
'executed_nodes',
|
||||
'failed_nodes',
|
||||
'skipped_nodes',
|
||||
])
|
||||
|
||||
export function getWorkflowDisplayContent(aggregatedResult) {
|
||||
if (aggregatedResult == null) return ''
|
||||
if (typeof aggregatedResult !== 'object' || Array.isArray(aggregatedResult)) {
|
||||
return typeof aggregatedResult === 'string'
|
||||
? aggregatedResult
|
||||
: JSON.stringify(aggregatedResult, null, 2)
|
||||
}
|
||||
|
||||
const core = aggregatedResult.analysis_core
|
||||
if (typeof core === 'string' && core.trim() !== '') return core
|
||||
|
||||
const combined = aggregatedResult.combined_analysis
|
||||
if (typeof combined === 'string' && combined.trim() !== '') return combined
|
||||
|
||||
const keys = Object.keys(aggregatedResult).filter((k) => !AGG_META_KEYS.has(k))
|
||||
if (keys.length === 1) {
|
||||
const v = aggregatedResult[keys[0]]
|
||||
if (typeof v === 'string') return v
|
||||
if (v != null && typeof v === 'object') return JSON.stringify(v, null, 2)
|
||||
return String(v)
|
||||
}
|
||||
|
||||
return JSON.stringify(aggregatedResult, null, 2)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user