pediatric-ai-scribe-v3/public/components/my-resources.html
Daniel 571a013d29
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 47s
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Android APK / Build signed APK (push) Successful in 2m9s
Forgejo Docker Build / Build Docker image (push) Successful in 11s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
feat: optional web search, admin-enabled and off by default
The one feature here that sends text outside the building, so the defaults are
the careful ones: disabled unless an administrator turns it on, opt-in per
generation even then, and the option is hidden entirely rather than shown as
something a user can tick and be refused.

Only the search query leaves. Library excerpts, the generated resource and
anything about the user never do. Both screens say so plainly, because a topic
typed while drafting clinical material can carry clinical detail and the
provider keeps its own logs.

Four providers behind one shape, so swapping changes nothing downstream: Tavily,
Serper over Google, Brave, and SearXNG — the only one where the query does not
reach a commercial third party at all, which is why it is worth supporting even
though it needs somewhere to run.

The tool description says when NOT to search, because a model handed a search
tool will reach for it constantly: not for settled clinical knowledge, which is
what the indexed library is for, and one search per resource. That last one is
enforced in the route with toolChoice: 'none' on the continuation rather than
trusted to the model.

A failed search never fails a generation — same contract as corpus retrieval.
The resource is written without it and the response says what was searched for
and what came back, so a query that left the network is visible rather than
silent.

The API key is masked on read and preserved when the field is left blank, the
handling the OIDC client secret already gets, so changing provider cannot
silently wipe a working key.

Verified on the running instance: with nothing configured, webSearchAvailable is
false, and a request asking for it anyway is ignored rather than honoured.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 15:47:06 +02:00

110 lines
5.7 KiB
HTML

<div class="card">
<div class="card-header">
<h3><i class="fas fa-folder-open"></i> My Resources</h3>
<span style="font-size:12px;color:var(--g500);">Private to you</span>
</div>
<div style="padding:16px;display:flex;flex-direction:column;gap:14px;">
<p style="margin:0;padding:8px 10px;background:var(--g100);border-radius:6px;font-size:12px;color:var(--g600);">
Teaching material you generate for yourself &mdash; a deck for tomorrow's session, a
handout, a summary. Nobody else sees these. Published Learning Hub content is separate
and stays with the moderators.
</p>
<div class="admin-row">
<label for="mr-topic" class="admin-row-label">Topic</label>
<input id="mr-topic" type="text" class="admin-control" placeholder="e.g. febrile seizures in under-fives" maxlength="300">
</div>
<div class="admin-row">
<label for="mr-kind" class="admin-row-label">Format</label>
<div style="flex:1;display:flex;gap:10px;align-items:center;flex-wrap:wrap;min-width:0;">
<select id="mr-kind" class="admin-control" style="max-width:220px;">
<option value="presentation">Presentation (slides)</option>
<option value="article">Article (prose)</option>
</select>
<label style="font-size:12px;color:var(--g600);display:flex;align-items:center;gap:6px;">
Slides
<input id="mr-slide-count" type="number" min="3" max="30" value="8" style="width:70px;font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;">
</label>
<label style="font-size:12px;color:var(--g600);display:flex;align-items:center;gap:6px;" id="mr-word-wrap" hidden>
Words
<input id="mr-word-count" type="number" min="200" max="3000" step="100" value="800" style="width:90px;font-size:13px;padding:5px 8px;border:1px solid var(--g300);border-radius:6px;">
</label>
</div>
</div>
<div class="admin-row">
<strong class="admin-row-label">Clinical library</strong>
<div style="flex:1;display:flex;flex-direction:column;gap:4px;min-width:0;">
<label style="display:flex;align-items:center;gap:8px;font-size:13px;">
<input type="checkbox" id="mr-use-corpus" checked>
Write from the indexed clinical library
</label>
<p style="margin:0;font-size:12px;color:var(--g500);">
Searches the corpus for your topic and writes from those excerpts, preferring them
over the model's own recall, and ends with a References section. Turn this off for a
topic the library does not cover.
</p>
</div>
</div>
<div class="admin-row" id="mr-model-row" hidden>
<label for="mr-model" class="admin-row-label">Model</label>
<div style="flex:1;display:flex;flex-direction:column;gap:4px;min-width:0;">
<select id="mr-model" class="admin-control" style="max-width:320px;"></select>
<p style="margin:0;font-size:12px;color:var(--g500);">
Only shown when an administrator has approved more than one. Otherwise the
configured model is used.
</p>
</div>
</div>
<div class="admin-row" id="mr-images-row" hidden>
<strong class="admin-row-label">Illustrations</strong>
<div style="flex:1;display:flex;flex-direction:column;gap:4px;min-width:0;">
<label style="display:flex;align-items:center;gap:8px;font-size:13px;">
<input type="checkbox" id="mr-with-images">
Let the model add an image where one genuinely helps
</label>
<p style="margin:0;font-size:12px;color:var(--g500);">
Off by default: a model handed a drawing tool will find a reason to use it, and
most teaching material does not want one. Images appear in your image history.
</p>
</div>
</div>
<div class="admin-row" id="mr-web-row" hidden>
<strong class="admin-row-label">Web search</strong>
<div style="flex:1;display:flex;flex-direction:column;gap:4px;min-width:0;">
<label style="display:flex;align-items:center;gap:8px;font-size:13px;">
<input type="checkbox" id="mr-web-search">
Let the model look something up online
</label>
<p style="margin:0;font-size:12px;color:var(--g500);">
For something newer than the library &mdash; a guideline published this year, a recent
approval. <strong>The search query leaves this network</strong> and reaches the provider
your administrator configured; the library excerpts and the resource itself never do.
Do not put anything identifying in the topic if you turn this on.
</p>
</div>
</div>
<div class="admin-row" style="align-items:flex-start;">
<label for="mr-refinement" class="admin-row-label">Instructions <span style="color:var(--g400);font-weight:400;">(optional)</span></label>
<textarea id="mr-refinement" class="admin-control" style="min-height:70px;resize:vertical;font-family:inherit;" placeholder="e.g. for FY1s, case-based, emphasise red flags"></textarea>
</div>
<div style="border-top:1px solid var(--g100);padding-top:12px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
<button id="btn-mr-generate" class="btn-sm btn-primary" type="button"><i class="fas fa-wand-magic-sparkles"></i> Generate</button>
<span id="mr-status" role="status" style="font-size:12px;color:var(--g600);"></span>
</div>
</div>
</div>
<div class="card" style="margin-top:14px;">
<div class="card-header">
<h3><i class="fas fa-book"></i> Library</h3>
<button id="btn-mr-refresh" class="btn-sm btn-ghost" type="button"><i class="fas fa-rotate"></i> Refresh</button>
</div>
<div id="mr-list" style="padding:12px 16px;display:flex;flex-direction:column;gap:6px;"></div>
</div>