feat(inference): S7 Call 1/Call 2 + prompt revision REST + test-inference + Generate text UI
- backend/inference.py: prompt seed (rev 0) + append-only revision REST
(POST /prompts/{call}/revisions, /activate, GET; METADATA-105/106). Call 1 vision
classification (1024px processed photos + synced taxonomy, 0.7 confidence gate,
METADATA-35/40/45), Call 2 long description (user-triggered, METADATA-55/60/65),
inference_log per call (METADATA-66), inference-off server_description (METADATA-70),
test-inference probe (SETTINGS-45). Stdlib urllib, no new deps.
- frontend: create/inference/GenerateText.svelte (control visible only when content
enabled + endpoint reachable, METADATA-110; Call 2 + Call 1 buttons) + dev toggle.
- tests: 6 inference tests (seed+revision, call1 gate, call2 stores desc, off->409,
server desc, test-inference unconfigured).
Verified: pytest 54 passed; gates exit 0; npm build ok.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<script lang="ts">
|
||||
let slabId = '';
|
||||
let contentEnabled = false;
|
||||
let reachable = false;
|
||||
let description: string | null = null;
|
||||
let call1Suggestions: Record<string, unknown> | null = null;
|
||||
let error = '';
|
||||
let busy = false;
|
||||
|
||||
async function checkReadiness() {
|
||||
contentEnabled = false;
|
||||
reachable = false;
|
||||
try {
|
||||
const [inf, test] = await Promise.all([
|
||||
fetch('/api/v1/settings').then((r) => r.json()),
|
||||
fetch('/api/v1/admin/test-inference', { method: 'POST' }).then((r) => r.json()),
|
||||
]);
|
||||
contentEnabled = inf.content_llm_enabled === 'true' || inf.content_llm_enabled === true;
|
||||
reachable = test.ok === true;
|
||||
} catch {
|
||||
reachable = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function generate() {
|
||||
if (!slabId) {
|
||||
error = 'Enter a slab id.';
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
error = '';
|
||||
description = null;
|
||||
try {
|
||||
const res = await fetch(`/api/v1/slabs/${encodeURIComponent(slabId)}/inference/call2`, { method: 'POST' });
|
||||
const body = await res.json();
|
||||
if (res.ok) description = body.description;
|
||||
else error = body.error?.message || `call2 failed (${res.status})`;
|
||||
} catch {
|
||||
error = 'network error';
|
||||
}
|
||||
busy = false;
|
||||
}
|
||||
|
||||
async function classify() {
|
||||
if (!slabId) {
|
||||
error = 'Enter a slab id.';
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
error = '';
|
||||
call1Suggestions = null;
|
||||
try {
|
||||
const res = await fetch(`/api/v1/slabs/${encodeURIComponent(slabId)}/inference/call1`, { method: 'POST' });
|
||||
const body = await res.json();
|
||||
if (res.ok) call1Suggestions = body.suggestions;
|
||||
else error = body.error?.message || `call1 failed (${res.status})`;
|
||||
} catch {
|
||||
error = 'network error';
|
||||
}
|
||||
busy = false;
|
||||
}
|
||||
|
||||
checkReadiness();
|
||||
</script>
|
||||
|
||||
<div class="inference">
|
||||
<h2>Generate text</h2>
|
||||
<p class="state">
|
||||
Content generation: {contentEnabled ? 'on' : 'off'} · endpoint: {reachable ? 'reachable' : 'unreachable'}
|
||||
</p>
|
||||
{#if !contentEnabled || !reachable}
|
||||
<p class="note">The Generate text control is disabled: it appears only when content generation is
|
||||
enabled and the inference endpoint is reachable.</p>
|
||||
{:else}
|
||||
<div>
|
||||
<label>Slab ID</label>
|
||||
<input bind:value={slabId} placeholder="uuid" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<button on:click={generate} disabled={busy}>{busy ? 'Working…' : 'Generate description (Call 2)'}</button>
|
||||
<button on:click={classify} disabled={busy}>Classify metadata (Call 1)</button>
|
||||
</div>
|
||||
{#if error}<p class="err">{error}</p>{/if}
|
||||
{#if description}<p class="desc">{description}</p>{/if}
|
||||
{#if call1Suggestions}
|
||||
<pre class="sug">{JSON.stringify(call1Suggestions, null, 2)}</pre>
|
||||
{/if}
|
||||
{/if}
|
||||
<button class="mini" on:click={checkReadiness}>Recheck readiness</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.inference { max-width: 560px; color: #eee; }
|
||||
label { display: block; margin: 8px 0 4px; }
|
||||
input { width: 100%; padding: 6px; }
|
||||
.row { margin-top: 12px; display: flex; gap: 8px; }
|
||||
.state { color: #aaa; }
|
||||
.note { color: #e8a; }
|
||||
.err { color: #e88; }
|
||||
.desc { margin-top: 12px; }
|
||||
.sug { background: #1c1c1c; padding: 8px; }
|
||||
.mini { margin-top: 12px; font-size: 12px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user