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,15 +152,25 @@ 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
const isStageRaw = data.is_stage_raw
return (
<tr key={key} style={{
borderBottom: '1px solid var(--border)',
background: isStageRaw && expertMode ? 'var(--surface)' : 'transparent'
}}>
<td style={{ <td style={{
padding: '6px 8px', padding: '6px 8px',
fontFamily: 'monospace', fontFamily: 'monospace',
color: 'var(--accent)', color: isStageRaw ? 'var(--text3)' : (isExtracted ? '#6B8E23' : 'var(--accent)'),
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
verticalAlign: 'top' verticalAlign: 'top',
fontSize: isStageRaw ? 10 : 11
}}> }}>
{isExtracted && '↳ '}
{isStageRaw && '🔬 '}
{key} {key}
</td> </td>
<td style={{ <td style={{
@ -164,7 +178,9 @@ function InsightCard({ ins, onDelete, defaultOpen=false, prompts=[] }) {
fontFamily: 'monospace', fontFamily: 'monospace',
wordBreak: 'break-word', wordBreak: 'break-word',
maxWidth: '400px', maxWidth: '400px',
verticalAlign: 'top' verticalAlign: 'top',
fontSize: isStageRaw ? 9 : 11,
color: isStageRaw ? 'var(--text3)' : 'var(--text1)'
}}> }}>
{data.value} {data.value}
</td> </td>
@ -172,12 +188,14 @@ function InsightCard({ ins, onDelete, defaultOpen=false, prompts=[] }) {
padding: '6px 8px', padding: '6px 8px',
color: 'var(--text3)', color: 'var(--text3)',
fontSize: 10, fontSize: 10,
verticalAlign: 'top' verticalAlign: 'top',
fontStyle: isExtracted ? 'italic' : 'normal'
}}> }}>
{data.description || '—'} {data.description || '—'}
</td> </td>
</tr> </tr>
))} )
})}
</tbody> </tbody>
</table> </table>
</div> </div>