Flexibles KI Prompt System #48

Merged
Lars merged 56 commits from develop into main 2026-03-26 14:49:48 +01:00
2 changed files with 81 additions and 36 deletions
Showing only changes of commit da803da816 - Show all commits

View File

@ -858,17 +858,41 @@ async def execute_unified_prompt(
stages_debug = result['debug'].get('stages', []) stages_debug = result['debug'].get('stages', [])
# First, collect stage outputs (outputs from base prompts in each stage) # First, collect stage outputs (outputs from base prompts in each stage)
stage_outputs = {} stage_outputs = {} # Raw stage outputs (for expert mode)
extracted_values = {} # Individual values extracted from JSON outputs (for normal mode)
for stage_debug in stages_debug: for stage_debug in stages_debug:
stage_num = stage_debug.get('stage', 0) stage_num = stage_debug.get('stage', 0)
stage_output = stage_debug.get('output', {}) stage_output = stage_debug.get('output', {})
if isinstance(stage_output, dict): if isinstance(stage_output, dict):
for output_key, output_value in stage_output.items(): for output_key, output_value in stage_output.items():
# Store stage outputs (e.g., stage_1_body) # Store raw stage output (for expert mode)
placeholder_key = f"stage_{stage_num}_{output_key}" placeholder_key = f"stage_{stage_num}_{output_key}"
stage_outputs[placeholder_key] = output_value stage_outputs[placeholder_key] = output_value
# Collect all resolved placeholders from prompts # If output is a dict/object, extract individual fields
if isinstance(output_value, dict):
for field_key, field_value in output_value.items():
# Store individual field (for normal mode)
# Use just the field name as key (e.g., "bmi" instead of "stage_1_body.bmi")
# This allows deduplication if multiple stages have the same field
if field_key not in extracted_values:
extracted_values[field_key] = {
'value': field_value if isinstance(field_value, str) else json.dumps(field_value, ensure_ascii=False),
'source_stage': stage_num,
'source_output': output_key
}
# Add extracted values from stage outputs (individual fields)
for field_key, field_data in extracted_values.items():
if field_key not in metadata['placeholders']:
metadata['placeholders'][field_key] = {
'value': field_data['value'],
'description': f"Aus Stage {field_data['source_stage']} ({field_data['source_output']})",
'is_extracted': True # Mark as extracted for filtering
}
# Collect all resolved placeholders from prompts (input placeholders)
for stage_debug in stages_debug: for stage_debug in stages_debug:
for prompt_debug in stage_debug.get('prompts', []): for prompt_debug in stage_debug.get('prompts', []):
resolved_keys = [] resolved_keys = []
@ -883,9 +907,10 @@ async def execute_unified_prompt(
# Get value: first try stage outputs, then cleaned_values # Get value: first try stage outputs, then cleaned_values
value = stage_outputs.get(key, cleaned_values.get(key, '')) value = stage_outputs.get(key, cleaned_values.get(key, ''))
# For stage output placeholders, add special description # For stage output placeholders (raw JSON), add special description
if key.startswith('stage_'): if key.startswith('stage_'):
desc = f"Output aus Stage {key.split('_')[1]} (Basis-Analyse)" desc = f"Rohdaten Stage {key.split('_')[1]} (Basis-Analyse JSON)"
is_stage_raw = True
else: else:
# Find description in catalog # Find description in catalog
desc = None desc = None
@ -895,10 +920,12 @@ async def execute_unified_prompt(
desc = matching[0].get('description', '') desc = matching[0].get('description', '')
break break
desc = desc or '' desc = desc or ''
is_stage_raw = False
metadata['placeholders'][key] = { metadata['placeholders'][key] = {
'value': value if isinstance(value, str) else json.dumps(value, ensure_ascii=False), 'value': value if isinstance(value, str) else json.dumps(value, ensure_ascii=False),
'description': desc 'description': desc,
'is_stage_raw': is_stage_raw # Mark raw stage outputs for expert mode
} }
# Save to database with metadata # Save to database with metadata

View File

@ -34,11 +34,15 @@ function InsightCard({ ins, onDelete, defaultOpen=false, prompts=[] }) {
const metadata = metadataRaw const metadata = metadataRaw
const allPlaceholders = placeholdersRaw const allPlaceholders = placeholdersRaw
// Filter placeholders: In normal mode, hide empty values // Filter placeholders: In normal mode, hide empty values and raw stage outputs
const placeholders = expertMode const placeholders = expertMode
? allPlaceholders ? allPlaceholders
: Object.fromEntries( : Object.fromEntries(
Object.entries(allPlaceholders).filter(([key, data]) => { Object.entries(allPlaceholders).filter(([key, data]) => {
// Hide raw stage outputs (JSON) in normal mode
if (data.is_stage_raw) return false
// Hide empty values
const val = data.value || '' const val = data.value || ''
return val.trim() !== '' && val !== 'nicht verfügbar' && val !== '[Nicht verfügbar]' return val.trim() !== '' && val !== 'nicht verfügbar' && val !== '[Nicht verfügbar]'
}) })
@ -148,36 +152,50 @@ function InsightCard({ ins, onDelete, defaultOpen=false, prompts=[] }) {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{Object.entries(placeholders).map(([key, data]) => ( {Object.entries(placeholders).map(([key, data]) => {
<tr key={key} style={{ borderBottom: '1px solid var(--border)' }}> const isExtracted = data.is_extracted
<td style={{ const isStageRaw = data.is_stage_raw
padding: '6px 8px',
fontFamily: 'monospace', return (
color: 'var(--accent)', <tr key={key} style={{
whiteSpace: 'nowrap', borderBottom: '1px solid var(--border)',
verticalAlign: 'top' background: isStageRaw && expertMode ? 'var(--surface)' : 'transparent'
}}> }}>
{key} <td style={{
</td> padding: '6px 8px',
<td style={{ fontFamily: 'monospace',
padding: '6px 8px', color: isStageRaw ? 'var(--text3)' : (isExtracted ? '#6B8E23' : 'var(--accent)'),
fontFamily: 'monospace', whiteSpace: 'nowrap',
wordBreak: 'break-word', verticalAlign: 'top',
maxWidth: '400px', fontSize: isStageRaw ? 10 : 11
verticalAlign: 'top' }}>
}}> {isExtracted && '↳ '}
{data.value} {isStageRaw && '🔬 '}
</td> {key}
<td style={{ </td>
padding: '6px 8px', <td style={{
color: 'var(--text3)', padding: '6px 8px',
fontSize: 10, fontFamily: 'monospace',
verticalAlign: 'top' wordBreak: 'break-word',
}}> maxWidth: '400px',
{data.description || '—'} verticalAlign: 'top',
</td> fontSize: isStageRaw ? 9 : 11,
</tr> color: isStageRaw ? 'var(--text3)' : 'var(--text1)'
))} }}>
{data.value}
</td>
<td style={{
padding: '6px 8px',
color: 'var(--text3)',
fontSize: 10,
verticalAlign: 'top',
fontStyle: isExtracted ? 'italic' : 'normal'
}}>
{data.description || '—'}
</td>
</tr>
)
})}
</tbody> </tbody>
</table> </table>
</div> </div>