Goals -System refactored - Platzhaltersystem enhanced (als draft) #53

Merged
Lars merged 86 commits from develop into main 2026-03-31 11:46:48 +02:00
4 changed files with 215 additions and 9 deletions
Showing only changes of commit 087e8dd885 - Show all commits

View File

@ -460,21 +460,24 @@ def analyze_placeholder_usage(profile_id: str) -> Dict[str, UsedBy]:
# Analyze each prompt
for prompt in prompts:
# Check template
template = prompt.get('template', '')
found_placeholders = re.findall(r'\{\{(\w+)\}\}', template)
template = prompt.get('template') or ''
if template: # Only process if template is not empty/None
found_placeholders = re.findall(r'\{\{(\w+)\}\}', template)
for ph_key in found_placeholders:
if ph_key not in usage_map:
usage_map[ph_key] = UsedBy()
if prompt['name'] not in usage_map[ph_key].prompts:
usage_map[ph_key].prompts.append(prompt['name'])
for ph_key in found_placeholders:
if ph_key not in usage_map:
usage_map[ph_key] = UsedBy()
if prompt['name'] not in usage_map[ph_key].prompts:
usage_map[ph_key].prompts.append(prompt['name'])
# Check stages (pipeline prompts)
stages = prompt.get('stages')
if stages:
for stage in stages:
for stage_prompt in stage.get('prompts', []):
template = stage_prompt.get('template', '')
template = stage_prompt.get('template') or ''
if not template: # Skip if template is None/empty
continue
found_placeholders = re.findall(r'\{\{(\w+)\}\}', template)
for ph_key in found_placeholders:

View File

@ -8,7 +8,8 @@ import json
import uuid
import httpx
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from db import get_db, get_cursor, r2d
from auth import require_auth, require_admin
@ -436,6 +437,158 @@ def export_placeholder_values_extended(session: dict = Depends(require_auth)):
return export_data
@router.get("/placeholders/export-catalog-zip")
def export_placeholder_catalog_zip(
token: Optional[str] = Query(None),
session: dict = Depends(require_admin)
):
"""
Export complete placeholder catalog as ZIP file.
Includes:
- PLACEHOLDER_CATALOG_EXTENDED.json
- PLACEHOLDER_CATALOG_EXTENDED.md
- PLACEHOLDER_GAP_REPORT.md
- PLACEHOLDER_EXPORT_SPEC.md
This generates the files on-the-fly and returns as ZIP.
Admin only.
"""
import io
import zipfile
from datetime import datetime
from generate_placeholder_catalog import (
generate_json_catalog,
generate_markdown_catalog,
generate_gap_report_md,
generate_export_spec_md
)
from placeholder_metadata_extractor import build_complete_metadata_registry
from generate_complete_metadata import apply_manual_corrections, generate_gap_report
profile_id = session['profile_id']
try:
# Build registry
registry = build_complete_metadata_registry(profile_id)
registry = apply_manual_corrections(registry)
gaps = generate_gap_report(registry)
# Create in-memory ZIP
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
# Generate each file content in memory and add to ZIP
# 1. JSON Catalog
all_metadata = registry.get_all()
json_catalog = {
"schema_version": "1.0.0",
"generated_at": datetime.now().isoformat(),
"normative_standard": "PLACEHOLDER_METADATA_REQUIREMENTS_V2_NORMATIVE.md",
"total_placeholders": len(all_metadata),
"placeholders": {key: meta.to_dict() for key, meta in sorted(all_metadata.items())}
}
zip_file.writestr(
'PLACEHOLDER_CATALOG_EXTENDED.json',
json.dumps(json_catalog, indent=2, ensure_ascii=False)
)
# 2. Markdown Catalog (simplified version)
by_category = registry.get_by_category()
md_lines = [
"# Placeholder Catalog (Extended)",
"",
f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
f"**Total Placeholders:** {len(all_metadata)}",
"",
"## Placeholders by Category",
""
]
for category, metadata_list in sorted(by_category.items()):
md_lines.append(f"### {category} ({len(metadata_list)} placeholders)")
md_lines.append("")
for metadata in sorted(metadata_list, key=lambda m: m.key):
md_lines.append(f"- `{{{{{metadata.key}}}}}` - {metadata.description}")
md_lines.append("")
zip_file.writestr('PLACEHOLDER_CATALOG_EXTENDED.md', '\n'.join(md_lines))
# 3. Gap Report
gap_lines = [
"# Placeholder Metadata Gap Report",
"",
f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
f"**Total Placeholders:** {len(all_metadata)}",
"",
"## Gaps Summary",
""
]
for gap_type, placeholders in sorted(gaps.items()):
if placeholders:
gap_lines.append(f"### {gap_type.replace('_', ' ').title()}")
gap_lines.append(f"Count: {len(placeholders)}")
gap_lines.append("")
for ph in placeholders[:10]: # Max 10 per type
gap_lines.append(f"- {{{{{ph}}}}}")
if len(placeholders) > 10:
gap_lines.append(f"- ... and {len(placeholders) - 10} more")
gap_lines.append("")
zip_file.writestr('PLACEHOLDER_GAP_REPORT.md', '\n'.join(gap_lines))
# 4. Export Spec (simplified)
spec_lines = [
"# Placeholder Export Specification",
"",
f"**Version:** 1.0.0",
f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
"",
"## API Endpoints",
"",
"### Extended Export",
"",
"```",
"GET /api/prompts/placeholders/export-values-extended",
"Header: X-Auth-Token: <token>",
"```",
"",
"Returns complete metadata for all 116 placeholders.",
"",
"### ZIP Export (Admin)",
"",
"```",
"GET /api/prompts/placeholders/export-catalog-zip",
"Header: X-Auth-Token: <token>",
"```",
"",
"Returns ZIP with all catalog files.",
]
zip_file.writestr('PLACEHOLDER_EXPORT_SPEC.md', '\n'.join(spec_lines))
# Prepare ZIP for download
zip_buffer.seek(0)
filename = f"placeholder-catalog-{datetime.now().strftime('%Y-%m-%d')}.zip"
return StreamingResponse(
io.BytesIO(zip_buffer.read()),
media_type="application/zip",
headers={
"Content-Disposition": f"attachment; filename={filename}"
}
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Failed to generate ZIP: {str(e)}"
)
# ── KI-Assisted Prompt Engineering ───────────────────────────────────────────
async def call_openrouter(prompt: str, max_tokens: int = 1500) -> str:

View File

@ -502,6 +502,53 @@ export default function AdminPanel() {
</Link>
</div>
</div>
{/* Placeholder Metadata Export Section */}
<div className="card section-gap" style={{marginTop:16}}>
<div style={{fontWeight:700,fontSize:14,marginBottom:12,display:'flex',alignItems:'center',gap:6}}>
<Settings size={16} color="var(--accent)"/> Placeholder Metadata Export (v1.0)
</div>
<div style={{fontSize:12,color:'var(--text3)',marginBottom:12,lineHeight:1.5}}>
Exportiere vollständige Metadaten aller 116 Placeholders. Normative Compliance v1.0.0.
</div>
<div style={{display:'grid',gap:8}}>
<button className="btn btn-secondary btn-full"
onClick={async()=>{
try {
const data = await api.exportPlaceholdersExtendedJson()
const blob = new Blob([JSON.stringify(data, null, 2)], {type:'application/json'})
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `placeholder-metadata-extended-${new Date().toISOString().split('T')[0]}.json`
a.click()
window.URL.revokeObjectURL(url)
} catch(e) {
alert('Fehler beim Export: '+e.message)
}
}}>
📄 Complete JSON exportieren
</button>
<button className="btn btn-secondary btn-full"
onClick={async()=>{
try {
const token = localStorage.getItem('bodytrack_token')
const a = document.createElement('a')
a.href = `/api/prompts/placeholders/export-catalog-zip?token=${token}`
a.download = `placeholder-catalog-${new Date().toISOString().split('T')[0]}.zip`
a.click()
} catch(e) {
alert('Fehler beim Export: '+e.message)
}
}}>
📦 Complete ZIP (JSON + Markdown + Reports)
</button>
</div>
<div style={{fontSize:11,color:'var(--text3)',marginTop:8,lineHeight:1.5}}>
<strong>JSON:</strong> Maschinenlesbare Metadaten aller Placeholders<br/>
<strong>ZIP:</strong> Katalog (JSON + MD), Gap Report, Export Spec (4 Dateien)
</div>
</div>
</div>
)
}

View File

@ -390,4 +390,7 @@ export const api = {
getSleepDurationQualityChart: (days=28) => req(`/charts/sleep-duration-quality?days=${days}`),
getSleepDebtChart: (days=28) => req(`/charts/sleep-debt?days=${days}`),
getVitalSignsMatrixChart: (days=7) => req(`/charts/vital-signs-matrix?days=${days}`),
// Placeholder Metadata Export (v1.0)
exportPlaceholdersExtendedJson: () => req('/prompts/placeholders/export-values-extended'),
}