feat: global placeholder export with values (Settings page)
Zentraler Export aller verfügbaren Platzhalter mit aktuellen Werten.
Backend:
- GET /api/prompts/placeholders/export-values
- Returns all placeholders organized by category
- Includes resolved values for current profile
- Includes metadata (description, example)
- Flat list + categorized structure
Frontend SettingsPage:
- Button "📊 Platzhalter exportieren"
- Downloads: placeholders-{profile}-{date}.json
- Shows all 38+ placeholders with current values
- Useful for:
- Understanding available data
- Debugging prompt templates
- Verifying placeholder resolution
Frontend api.js:
- exportPlaceholderValues()
Export Format:
{
"export_date": "2026-03-26T...",
"profile_id": "...",
"count": 38,
"all_placeholders": { "name": "Lars", ... },
"placeholders_by_category": {
"Profil": [...],
"Körper": [...],
...
}
}
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7f94a41965
commit
555ff62b56
|
|
@ -217,6 +217,54 @@ def list_placeholders(session: dict=Depends(require_auth)):
|
||||||
return get_placeholder_catalog(profile_id)
|
return get_placeholder_catalog(profile_id)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/placeholders/export-values")
|
||||||
|
def export_placeholder_values(session: dict = Depends(require_auth)):
|
||||||
|
"""
|
||||||
|
Export all available placeholders with their current resolved values.
|
||||||
|
|
||||||
|
Returns JSON export suitable for download with all placeholders
|
||||||
|
resolved for the current user's profile.
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
profile_id = session['profile_id']
|
||||||
|
|
||||||
|
# Get all resolved placeholder values
|
||||||
|
resolved_values = get_placeholder_example_values(profile_id)
|
||||||
|
|
||||||
|
# Clean up keys (remove {{ }})
|
||||||
|
cleaned_values = {
|
||||||
|
key.replace('{{', '').replace('}}', ''): value
|
||||||
|
for key, value in resolved_values.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get catalog for metadata
|
||||||
|
catalog = get_placeholder_catalog(profile_id)
|
||||||
|
|
||||||
|
# Organize by category with metadata
|
||||||
|
export_data = {
|
||||||
|
'export_date': datetime.now().isoformat(),
|
||||||
|
'profile_id': profile_id,
|
||||||
|
'placeholders_by_category': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for category, items in catalog.items():
|
||||||
|
export_data['placeholders_by_category'][category] = []
|
||||||
|
for item in items:
|
||||||
|
key = item['key'].replace('{{', '').replace('}}', '')
|
||||||
|
export_data['placeholders_by_category'][category].append({
|
||||||
|
'key': item['key'],
|
||||||
|
'description': item['description'],
|
||||||
|
'value': cleaned_values.get(key, 'nicht verfügbar'),
|
||||||
|
'example': item.get('example')
|
||||||
|
})
|
||||||
|
|
||||||
|
# Also include flat list for easy access
|
||||||
|
export_data['all_placeholders'] = cleaned_values
|
||||||
|
export_data['count'] = len(cleaned_values)
|
||||||
|
|
||||||
|
return export_data
|
||||||
|
|
||||||
|
|
||||||
# ── KI-Assisted Prompt Engineering ───────────────────────────────────────────
|
# ── KI-Assisted Prompt Engineering ───────────────────────────────────────────
|
||||||
|
|
||||||
async def call_openrouter(prompt: str, max_tokens: int = 1500) -> str:
|
async def call_openrouter(prompt: str, max_tokens: int = 1500) -> str:
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,23 @@ export default function SettingsPage() {
|
||||||
setEditingId(null)
|
setEditingId(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleExportPlaceholders = async () => {
|
||||||
|
try {
|
||||||
|
const data = await api.exportPlaceholderValues()
|
||||||
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url
|
||||||
|
a.download = `placeholders-${activeProfile?.name || 'profile'}-${new Date().toISOString().split('T')[0]}.json`
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click()
|
||||||
|
document.body.removeChild(a)
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
} catch (e) {
|
||||||
|
alert('Fehler beim Export: ' + e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="page-title">Einstellungen</h1>
|
<h1 className="page-title">Einstellungen</h1>
|
||||||
|
|
@ -409,6 +426,16 @@ export default function SettingsPage() {
|
||||||
<span className="badge-button-description">maschinenlesbar, alles in einer Datei</span>
|
<span className="badge-button-description">maschinenlesbar, alles in einer Datei</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
<button className="btn btn-full"
|
||||||
|
onClick={handleExportPlaceholders}
|
||||||
|
style={{ background: 'var(--surface2)', border: '1px solid var(--border)' }}>
|
||||||
|
<div className="badge-button-layout">
|
||||||
|
<div className="badge-button-header">
|
||||||
|
<span><BarChart3 size={14}/> Platzhalter exportieren</span>
|
||||||
|
</div>
|
||||||
|
<span className="badge-button-description">alle verfügbaren Platzhalter mit aktuellen Werten</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</div>
|
||||||
<p style={{fontSize:11,color:'var(--text3)',marginTop:8}}>
|
<p style={{fontSize:11,color:'var(--text3)',marginTop:8}}>
|
||||||
|
|
|
||||||
|
|
@ -326,4 +326,7 @@ export const api = {
|
||||||
if (overwrite) params.append('overwrite', 'true')
|
if (overwrite) params.append('overwrite', 'true')
|
||||||
return req(`/prompts/import?${params}`, json(data))
|
return req(`/prompts/import?${params}`, json(data))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Placeholder Export
|
||||||
|
exportPlaceholderValues: () => req('/prompts/placeholders/export-values'),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user