Download ProjectIntakeTower/verifier/generate_learning_graphic.py from smlflg/AgentProjectMinenraeumer: direct link, hf CLI and curl.
- Browser
- Download file 9.11 kB
-
https://huggingface.co/smlflg/AgentProjectMinenraeumer/resolve/main/ProjectIntakeTower/verifier/generate_learning_graphic.py
- Command line
-
hf download hf://smlflg/AgentProjectMinenraeumer/ProjectIntakeTower/verifier/generate_learning_graphic.py
-
curl -L -o generate_learning_graphic.py https://huggingface.co/smlflg/AgentProjectMinenraeumer/resolve/main/ProjectIntakeTower/verifier/generate_learning_graphic.py
9.11 kB
| #!/usr/bin/env python3 | |
| import json, re, html, textwrap | |
| from pathlib import Path | |
| from PIL import Image, ImageDraw, ImageFont | |
| ROOT=Path(__file__).resolve().parents[1] | |
| TRIAGE=ROOT/'triage' | |
| OUT=ROOT/'visual_summary' | |
| OUT.mkdir(parents=True,exist_ok=True) | |
| def load(p): return json.loads(Path(p).read_text(encoding='utf-8')) | |
| def short(path): | |
| s=path.replace('/home/smlflg/Projekte/','').replace('/home/smlflg/','~/' ) | |
| return s if len(s)<=48 else '…'+s[-47:] | |
| def wrap(draw, text, font, width): | |
| words=str(text).split(); lines=[]; cur='' | |
| for w in words: | |
| test=(cur+' '+w).strip() | |
| if draw.textbbox((0,0),test,font=font)[2] <= width: cur=test | |
| else: | |
| if cur: lines.append(cur) | |
| cur=w | |
| if cur: lines.append(cur) | |
| return lines | |
| def top_names(items,n=8): return [short(x['path']) for x in items[:n]] | |
| def main(): | |
| pri=load(TRIAGE/'PROJECT_PRIORITIZATION.json') | |
| summary=load(TRIAGE/'PROJECT_PRIORITIZATION_SUMMARY.json') | |
| keep=pri['categories']['KEEP']; urgent=pri['categories']['URGENT']; merge=pri['categories']['MERGE']; pause=pri['categories']['PAUSE']; archive=pri['categories']['ARCHIVE']; token=pri['categories']['TOKEN_BURN_CANDIDATE']; human=pri['categories']['HUMAN_DECISION_REQUIRED'] | |
| bypath={r['path']:r for r in pri['projects']} | |
| def get(path): return bypath.get(path, {'path':path,'score':0,'dirty_count':0,'categories':[]}) | |
| top10=[ | |
| get('/home/smlflg/Projekte/Sidecar-Workspace/Sidecar-V7'), | |
| get('/home/smlflg/Projekte/Zentrale'), | |
| get('/home/smlflg/Projekte/ACT-agentcommandotower'), | |
| get('/home/smlflg/Projekte/AIOS-Cockpit'), | |
| get('/home/smlflg/Projekte/AgentArena'), | |
| get('/home/smlflg/Projekte/Jobs_Selbständigkeit_Geldverdienen/AgentTestUniSupport'), | |
| get('/home/smlflg/Projekte/Sidecar-Workspace/Sidecar-V8'), | |
| get('/home/smlflg/.hermes'), | |
| get('/home/smlflg/Projekte/UEBER_AGENT'), | |
| get('/home/smlflg/Projekte/PromptGarage'), | |
| ] | |
| gold=[get(p) for p in ['/home/smlflg/Projekte/Zentrale','/home/smlflg/Projekte/ACT-agentcommandotower','/home/smlflg/Projekte/AIOS-Cockpit','/home/smlflg/Projekte/Sidecar-Workspace/Sidecar-V8','/home/smlflg/.hermes']] | |
| almost=[get(p) for p in ['/home/smlflg/Projekte/Jobs_Selbständigkeit_Geldverdienen/AgentTestUniSupport','/home/smlflg/Projekte/Sidecar-Workspace/Sidecar-V7','/home/smlflg/Projekte/ClaudeCodePanel','/home/smlflg/Projekte/PromptGarage']] | |
| needs_tests=[r for r in keep if 'python' in (r.get('tech') or '').lower()][:7] | |
| tomorrow=[get('/home/smlflg/Projekte/Zentrale'), get('/home/smlflg/Projekte/ACT-agentcommandotower'), get('/home/smlflg/.hermes')] | |
| garbage=archive[:8] | |
| data={ | |
| 'title':'Samuel Project Map — Gold, Müll, Morgen', | |
| 'counts':summary, | |
| 'top10':top10,'gold':gold,'garbage':garbage,'almost_done':almost,'needs_tests':needs_tests, | |
| 'scope_creep':token[:8],'archive':archive[:8],'tomorrow':tomorrow,'human':human[:8], | |
| 'rules':[ | |
| 'KEEP = weiterführen, aber mit Verifier', | |
| 'MERGE = wertvoll, aber nicht separat weiterbauen', | |
| 'PAUSE = nicht löschen, aber keine Tokens mehr verbrennen', | |
| 'ARCHIVE = nur nach Human Gate; zuerst Manifest sichern', | |
| 'URGENT = dirty/risikoreich: morgen zuerst stabilisieren' | |
| ] | |
| } | |
| (OUT/'learning_graphic_data.json').write_text(json.dumps(data,indent=2,ensure_ascii=False),encoding='utf-8') | |
| W,H=1800,2400 | |
| bg='#08111f'; card='#101b2d'; stroke='#26364f'; text='#e5eefc'; muted='#94a3b8' | |
| img=Image.new('RGB',(W,H),bg); d=ImageDraw.Draw(img) | |
| def font(size,bold=False): | |
| p='/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf' if bold else '/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf' | |
| return ImageFont.truetype(p,size) | |
| f_title=font(60,True); f_h=font(36,True); f=font(25); f_s=font(20); f_tiny=font(17) | |
| d.text((70,55),'🧭 Samuel Project Map',fill='#67e8f9',font=f_title) | |
| d.text((72,130),'Was ist Gold, was ist Müll, was braucht Tests, was morgen zuerst?',fill=muted,font=f) | |
| # metric pills | |
| x=70; y=190 | |
| pills=[('KEEP',summary['KEEP'],'#22c55e'),('MERGE',summary['MERGE'],'#a78bfa'),('PAUSE',summary['PAUSE'],'#94a3b8'),('ARCHIVE',summary['ARCHIVE'],'#f97316'),('URGENT',summary['URGENT'],'#ef4444'),('TOKEN BURN',summary['TOKEN_BURN_CANDIDATE'],'#facc15')] | |
| for label,val,col in pills: | |
| d.rounded_rectangle((x,y,x+250,y+64),radius=18,fill='#0f172a',outline=col,width=3) | |
| d.text((x+18,y+14),f'{label}: {val}',fill=col,font=f_s) | |
| x+=270 | |
| def card_box(x,y,w,h,title,color,items,subtitle=None): | |
| d.rounded_rectangle((x,y,x+w,y+h),radius=24,fill=card,outline=color,width=4) | |
| d.text((x+28,y+22),title,fill=color,font=f_h) | |
| cy=y+78 | |
| if subtitle: | |
| for ln in wrap(d,subtitle,f_s,w-56)[:2]: | |
| d.text((x+28,cy),ln,fill=muted,font=f_s); cy+=27 | |
| cy+=8 | |
| for i,it in enumerate(items): | |
| name=short(it['path']) if isinstance(it,dict) else str(it) | |
| score=it.get('score') if isinstance(it,dict) else None | |
| dirty=it.get('dirty_count') if isinstance(it,dict) else None | |
| line=f'{i+1}. {name}' | |
| if score is not None: line+=f' s={score}' | |
| if dirty: line+=f' dirty={dirty}' | |
| for j,ln in enumerate(wrap(d,line,f_s,w-70)[:2]): | |
| d.text((x+30,cy),ln,fill=text if i<5 else muted,font=f_s); cy+=25 | |
| cy+=6 | |
| if cy>y+h-30: break | |
| card_box(70,290,800,535,'🏆 Deine 10 wichtigsten Projekte','#22d3ee',top10,'Das ist dein echtes Agentic-OS: Control Tower + Sidecar + Hermes + Eval + Uni.') | |
| card_box(930,290,800,535,'💎 Gold','#22c55e',gold,'Nicht neu anfangen. Diese Kerne stabilisieren und verbinden.') | |
| card_box(70,870,530,420,'🗑️ Müll / Cache','#fb923c',garbage,'Vor allem repo_cache/fixtures. Erst Manifest, dann archivieren.') | |
| card_box(635,870,530,420,'✅ Fast fertig','#84cc16',almost,'Hat klare Idee/README oder MVP-Signal. Braucht Closure statt Neubau.') | |
| card_box(1200,870,530,420,'🧪 Braucht nur Tests','#38bdf8',needs_tests,'Nicht weiter bauen, bevor Smoke-Test/pytest grün ist.') | |
| card_box(70,1335,530,455,'🌀 Scope-Creep','#facc15',token[:8],'Viele Pläne/TODOs/Agent-Spuren. Token-Burn-Gefahr.') | |
| card_box(635,1335,530,455,'📦 Archivieren','#fb7185',archive[:8],'Nur Human-Gated. Nichts löschen; erst Patch/Manifest sichern.') | |
| card_box(1200,1335,530,455,'🌅 Morgen als erstes','#c084fc',tomorrow,'1) Zentrale stabilisieren 2) ACT als Closure-Prozess 3) Hermes dirty state sichern') | |
| # rules bottom | |
| d.rounded_rectangle((70,1840,1660,455+1840),radius=24,fill='#0f172a',outline='#64748b',width=3) | |
| d.text((100,1870),'🧠 Lernregel',fill='#e879f9',font=f_h) | |
| yy=1930 | |
| for rule in data['rules']: | |
| for ln in wrap(d,'• '+rule,f,1480): | |
| d.text((110,yy),ln,fill=text,font=f); yy+=34 | |
| d.text((100,2220),'Morgen-Default: Keine neuen Projekte. Erst Zentrale + ACT + Hermes in einen verifizierbaren Loop bringen.',fill='#67e8f9',font=f) | |
| d.text((100,2280),'Human Gate bleibt hart: Archive/Merge/Commit/Push nur nach expliziter Freigabe.',fill='#fca5a5',font=f_s) | |
| img.save(OUT/'project_learning_graphic.png') | |
| # HTML companion | |
| def ul(items): | |
| return '<ul>'+''.join(f'<li><code>{html.escape(short(x["path"]))}</code> <span>s={x.get("score")}</span></li>' for x in items)+'</ul>' | |
| html_doc=f'''<!doctype html><html><head><meta charset="utf-8"><title>Samuel Project Map</title><style>body{{background:{bg};color:{text};font-family:Menlo,monospace;margin:0;padding:36px}}.grid{{display:grid;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));gap:18px}}.card{{background:{card};border:1px solid {stroke};border-radius:18px;padding:20px}}h1{{color:#67e8f9}}h2{{color:#c084fc}}code{{color:#7dd3fc}}img{{max-width:100%;border-radius:20px;border:1px solid #334155}}</style></head><body><h1>Samuel Project Map — Lern-Grafik</h1><p><a href="project_learning_graphic.png">PNG öffnen</a></p><img src="project_learning_graphic.png"><div class="grid"><div class="card"><h2>10 wichtigste Projekte</h2>{ul(top10)}</div><div class="card"><h2>Gold</h2>{ul(gold)}</div><div class="card"><h2>Müll / Cache</h2>{ul(garbage)}</div><div class="card"><h2>Fast fertig</h2>{ul(almost)}</div><div class="card"><h2>Braucht Tests</h2>{ul(needs_tests)}</div><div class="card"><h2>Scope-Creep</h2>{ul(token[:8])}</div><div class="card"><h2>Archivieren</h2>{ul(archive[:8])}</div><div class="card"><h2>Morgen zuerst</h2>{ul(tomorrow)}</div></div></body></html>''' | |
| (OUT/'project_learning_graphic.html').write_text(html_doc,encoding='utf-8') | |
| result={'status':'succeeded','png':str(OUT/'project_learning_graphic.png'),'html':str(OUT/'project_learning_graphic.html'),'data':str(OUT/'learning_graphic_data.json'),'top10':[x['path'] for x in top10]} | |
| (OUT/'result.json').write_text(json.dumps(result,indent=2,ensure_ascii=False),encoding='utf-8') | |
| print(json.dumps(result,indent=2)) | |
| if __name__=='__main__': main() | |