Duplicate / license_curation.py
Theflame47's picture
Update license_curation.py
7e89994 verified
Raw
History Blame Contribute Delete
4.62 kB
# license_curation.py
from typing import Any, Dict, List
from fastapi import APIRouter
from fastapi.responses import HTMLResponse, JSONResponse
import html
from data import get_pages, ensure_page_loaded, flatten_models, license_label_and_url, is_complete
router = APIRouter()
def _rows(models: List[Dict[str, Any]]) -> str:
from data import model_id
out = []
for m in models:
mid = html.escape(model_id(m))
label, url = license_label_and_url(m)
label_h = html.escape(label or "Unknown")
lic_html = f"<a href='{html.escape(url)}' target='_blank' rel='noopener'>{label_h}</a>" if url else label_h
out.append(f"<tr><td class='id'>{mid}</td><td class='lic'>{lic_html}</td></tr>")
return "\n".join(out)
def _counts(models: List[Dict[str, Any]]) -> Dict[str, Any]:
total, known, unknown = 0, 0, 0
by_label: Dict[str, int] = {}
for m in models:
total += 1
label, _ = license_label_and_url(m)
if label and label.lower() != "unknown":
known += 1
else:
unknown += 1
by_label[label] = by_label.get(label, 0) + 1
return {"total": total, "known": known, "unknown": unknown, "by_label": by_label}
def _shell(table_rows: str) -> str:
return f"""
<!doctype html>
<html><head><meta charset="utf-8" />
<title>License Curation</title>
<style>
body {{ font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; margin: 24px; }}
.meta {{ margin-bottom: 12px; color: #444; display:flex; gap:16px; align-items:center; flex-wrap:wrap; }}
.pill {{ display:inline-block; padding:2px 8px; border:1px solid #ddd; border-radius:999px; font-size:12px; color:#333; }}
table.grid {{ width:100%; border-collapse: collapse; }}
table.grid th, table.grid td {{ border-bottom:1px solid #eee; padding:10px; vertical-align:top; }}
table.grid th {{ text-align:left; background:#fafafa; }}
.id {{ font-weight:600; white-space:nowrap; }}
.lic {{ white-space:nowrap; }}
#logBtn {{ position:fixed; right:20px; bottom:20px; padding:10px 14px; border:none; border-radius:999px; background:#111; color:#fff; cursor:pointer; }}
#logPanel {{ position:fixed; right:20px; bottom:70px; width:320px; max-height:50vh; overflow:auto; background:#fff; border:1px solid #ddd; border-radius:12px; box-shadow:0 10px 24px rgba(0,0,0,0.12); padding:12px; display:none; }}
#logPanel h3 {{ margin:0 0 8px 0; font-size:14px; }}
#logPanel .row {{ display:flex; justify-content:space-between; font-size:13px; padding:2px 0; }}
#byLabel {{ margin-top:8px; font-size:12px; max-height:28vh; overflow:auto; }}
</style></head>
<body>
<div class="meta">
<strong>License Curation</strong>
<span class="pill">catalog complete: {"yes" if is_complete() else "no"}</span>
<span class="pill">pages loaded: {len(get_pages())}</span>
</div>
<table class="grid">
<thead><tr><th>ID</th><th>License</th></tr></thead>
<tbody>{table_rows}</tbody>
</table>
<button id="logBtn" onclick="toggleLog()">Log</button>
<div id="logPanel">
<h3>License log</h3>
<div class="row"><span>Total models</span><span id="tot">–</span></div>
<div class="row"><span>Known licenses</span><span id="kn">–</span></div>
<div class="row"><span>Unknown licenses</span><span id="un">–</span></div>
<div id="byLabel"></div>
</div>
<script>
function toggleLog() {{
const p = document.getElementById('logPanel');
p.style.display = (p.style.display === 'block') ? 'none' : 'block';
if (p.style.display === 'block') refreshLog();
}}
function refreshLog() {{
fetch('/licenses/stats').then(r=>r.json()).then(s => {{
document.getElementById('tot').textContent = s.total;
document.getElementById('kn').textContent = s.known;
document.getElementById('un').textContent = s.unknown;
const bl = document.getElementById('byLabel');
bl.innerHTML = '';
Object.entries(s.by_label || {{}}).sort((a,b)=>b[1]-a[1]).forEach(([k,v]) => {{
const d = document.createElement('div'); d.className='row';
d.innerHTML = `<span>${{k}}</span><span>${{v}}</span>`;
bl.appendChild(d);
}});
}}).catch(()=>{{}});
}}
</script>
</body></html>
"""
@router.get("/licenses", response_class=HTMLResponse)
def licenses_page():
if not get_pages():
try:
ensure_page_loaded(0)
except Exception:
pass
rows = _rows(flatten_models())
return HTMLResponse(_shell(rows))
@router.get("/licenses/stats")
def licenses_stats():
return JSONResponse(_counts(flatten_models()))