inou/portal/templates/api.tmpl

144 lines
6.7 KiB
Cheetah

{{define "api"}}
<style>
.api-container { max-width: 720px; margin: 0 auto; padding: 40px 20px; }
.api-container h1 { font-size: 2rem; margin-bottom: 0.5rem; }
.api-container .subtitle { color: var(--text-muted); margin-bottom: 2rem; }
.ai-box { background: var(--cream-light); border-radius: 8px; padding: 1.5rem; margin-bottom: 2rem; }
.ai-box h2 { font-size: 1.1rem; margin: 0 0 1rem 0; color: var(--accent); }
.ai-box h3 { font-size: 0.95rem; margin: 1.5rem 0 0.5rem 0; }
.ai-box:first-of-type h3:first-of-type { margin-top: 0.5rem; }
.ai-box p { margin: 0.5rem 0; font-size: 0.9rem; }
.ai-box code { background: #2d2d2d; color: #f8f8f2; padding: 2px 6px; border-radius: 4px; font-size: 0.85rem; }
.ai-box pre { background: #2d2d2d; color: #f8f8f2; padding: 12px 16px; border-radius: 6px; font-size: 0.85rem; overflow-x: auto; margin: 0.5rem 0; }
.ai-box ul { margin: 0.5rem 0; padding-left: 1.5rem; font-size: 0.9rem; }
.ai-box li { margin: 0.25rem 0; }
.guid-display { background: #2d2d2d; color: #6c6; padding: 8px 12px; border-radius: 6px; font-family: monospace; font-size: 0.9rem; margin: 0.5rem 0; display: inline-block; }
.endpoint { background: white; border: 1px solid var(--border); border-radius: 8px; padding: 1rem 1.25rem; margin: 1rem 0; }
.endpoint .method { color: #22863a; font-weight: 600; font-size: 0.85rem; }
.endpoint .url { color: var(--accent); font-family: monospace; font-size: 0.9rem; }
.endpoint p { margin: 0.5rem 0 0 0; font-size: 0.9rem; color: var(--text-muted); }
.note { background: #fef3cd; border-radius: 6px; padding: 0.75rem 1rem; margin: 1rem 0; font-size: 0.9rem; }
.section-label { font-size: 0.75rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted); margin: 2rem 0 0.5rem 0; }
</style>
<div class="api-container">
<h1>API</h1>
<p class="subtitle">Access your health dossier data programmatically — or let AI do it for you.</p>
{{if .Dossier}}
<div class="ai-box">
<h2>{{.T.api_token}}</h2>
{{if .APIToken}}
<p>{{.T.api_token_use}}</p>
<div style="display: flex; align-items: center; gap: 8px; margin: 0.5rem 0;">
<input type="text" id="api-token" value="{{.APIToken}}" readonly style="flex: 1; background: #2d2d2d; color: #6c6; padding: 8px 12px; border-radius: 6px; font-family: monospace; font-size: 0.9rem; border: none;">
<button onclick="copyToken()" class="btn btn-small" style="white-space: nowrap;">{{.T.copy}}</button>
</div>
<p style="color: var(--text-muted); font-size: 0.85rem; margin-top: 0.75rem;">{{.T.api_token_warning}}</p>
<form method="POST" action="/api/token/regenerate" style="margin-top: 1rem;">
<button type="submit" class="btn btn-small btn-secondary" onclick="return confirm('{{.T.api_token_regenerate_confirm}}')">{{.T.api_token_regenerate}}</button>
</form>
{{else}}
<p>{{.T.api_token_none}}</p>
<form method="POST" action="/api/token/generate" style="margin-top: 1rem;">
<button type="submit" class="btn btn-primary">{{.T.api_token_generate}}</button>
</form>
{{end}}
</div>
<script>
function copyToken() {
const input = document.getElementById('api-token');
input.select();
document.execCommand('copy');
const btn = event.target;
const original = btn.textContent;
btn.textContent = '✓';
setTimeout(() => btn.textContent = original, 1500);
}
</script>
{{end}}
<h2 style="margin-top: 2.5rem;">{{.T.api_authentication}}</h2>
<p>{{.T.api_auth_instructions}}</p>
<pre style="background: #2d2d2d; color: #f8f8f2; padding: 12px 16px; border-radius: 6px; font-size: 0.85rem; margin: 1rem 0;">Authorization: Bearer YOUR_API_TOKEN</pre>
<h2 style="margin-top: 2.5rem;">Endpoints</h2>
<p class="section-label">Dossiers</p>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/dossiers</span>
<p>List all dossiers accessible to this account (your own + any shared with you).</p>
</div>
<p class="section-label">Imaging</p>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/dossiers/{id}/entries?category=imaging</span>
<p>List all imaging studies in a dossier. Returns study ID, date, description, and series count.</p>
</div>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/entries/{study_id}/children</span>
<p>List series in a study. Optional: <code>?filter=SAG</code> or <code>?filter=T1</code> to filter by description.</p>
</div>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/entries/{series_id}/children</span>
<p>List slices with position data (mm coordinates, orientation, pixel spacing).</p>
</div>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/entries/{slice_id}?detail=full</span>
<p>Get slice image as PNG. Optional: <code>&ww=WIDTH&wc=CENTER</code> for windowing.</p>
</div>
<p class="section-label">Genome</p>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/dossiers/{id}/entries?category=genome</span>
<p>List genome variant categories: medication, cardiovascular, metabolism, fertility, traits, longevity.</p>
</div>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/dossiers/{id}/genome?search=MTHFR</span>
<p>Query genome variants. Optional filters: <code>&category=medication</code>, <code>&rsids=rs1234,rs5678</code>, <code>&min_magnitude=2</code></p>
</div>
<p class="section-label">Labs</p>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/dossiers/{id}/labs/tests</span>
<p>List all available lab test names for a dossier.</p>
</div>
<div class="endpoint">
<span class="method">GET</span> <span class="url">/api/v1/dossiers/{id}/labs/results?names=TSH,T4</span>
<p>Get lab results. Required: <code>&names=</code> (comma-separated). Optional: <code>&from=2024-01-01</code>, <code>&to=2024-12-31</code>, <code>&latest=true</code></p>
</div>
<div class="note">
<strong>Text Format:</strong> Add <code>&format=text</code> to any endpoint for AI-friendly plain text output instead of JSON.
</div>
<h2 style="margin-top: 2.5rem;">Example</h2>
<pre style="background: #2d2d2d; color: #f8f8f2; padding: 16px; border-radius: 8px; font-size: 0.85rem; overflow-x: auto;"># List your dossiers
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://inou.com/api/v1/dossiers
# List imaging studies
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://inou.com/api/v1/dossiers/DOSSIER_ID/entries?category=imaging
# Query genome variants
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://inou.com/api/v1/dossiers/DOSSIER_ID/genome?search=MTHFR</pre>
</div>
{{end}}