From cef9178d8db4e0d13d648c4bec554616e59f3456 Mon Sep 17 00:00:00 2001 From: KansaiGaijin <83641841+KansaiGaijin@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:49:21 +1200 Subject: [PATCH] =?UTF-8?q?fix:=20chunk=20upload=20race=20=E2=80=94=20alwa?= =?UTF-8?q?ys=20return=20the=20completed=20response=20with=20filepath;=20a?= =?UTF-8?q?dd=20campaign=20name=20to=20setup=20wizard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.example.yml | 3 +++ frontend/src/api.ts | 17 ++++++++++++++++- frontend/src/pages/Setup.tsx | 22 +++++++++++++++++++--- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/docker-compose.example.yml b/docker-compose.example.yml index b3342b5..700063f 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -20,6 +20,9 @@ services: # Set to "true" after onboarding completes. NAT20_ONBOARDING_COMPLETED: "false" + # Campaign name is set during the setup wizard (step 2). + # You can also rename it later in Settings → Campaigns. + # ── Transcription ───────────────────────────────────── NAT20_WHISPER_MODEL: medium NAT20_WHISPER_COMPUTE_TYPE: int8 diff --git a/frontend/src/api.ts b/frontend/src/api.ts index f350edd..2341251 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -100,6 +100,17 @@ export const campaignApi = { }; export const api = { + // Campaign + updateCampaign: async (id: string, body: Partial>): Promise => { + const res = await fetch(`${BASE_URL}/campaigns/${encodeURIComponent(id)}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + if (!res.ok) throw new Error('Failed to update campaign'); + return res.json(); + }, + // Settings getSettings: async (): Promise => { const res = await fetch(`${BASE_URL}/settings`); @@ -241,6 +252,7 @@ export const api = { }; let lastResult: any = null; + let completedResult: any = null; for (let i = 0; i < totalChunks; i += CONCURRENCY) { const batch = []; for (let j = i; j < Math.min(i + CONCURRENCY, totalChunks); j++) { @@ -248,9 +260,12 @@ export const api = { } const results = await Promise.all(batch); lastResult = results[results.length - 1]; + if (!completedResult) { + completedResult = results.find(r => r.status === 'completed'); + } onProgress(Math.round((Math.min(i + CONCURRENCY, totalChunks) / totalChunks) * 100)); } - return lastResult; + return completedResult || lastResult; }, // Files diff --git a/frontend/src/pages/Setup.tsx b/frontend/src/pages/Setup.tsx index 7163d1d..82f9e62 100644 --- a/frontend/src/pages/Setup.tsx +++ b/frontend/src/pages/Setup.tsx @@ -20,18 +20,22 @@ const DEFAULT_SETTINGS: Record = { export default function Setup({ onComplete }: { onComplete: () => void }) { const [step, setStep] = useState(1); + const [campaignName, setCampaignName] = useState("Default Campaign"); const [settings, setSettings] = useState>(DEFAULT_SETTINGS); const [saving, setSaving] = useState(false); const [error, setError] = useState(""); - // On first load, try to fetch existing settings from the "default" campaign - // (which is always created by init_db). + // On first load, try to fetch existing settings and name from the "default" campaign. useEffect(() => { api.getCampaignSettings('default') .then(data => { if (data) setSettings(prev => ({ ...prev, ...data })); }) .catch(() => {}); + fetch('/api/campaigns/default') + .then(r => r.ok ? r.json() : null) + .then(c => { if (c?.name) setCampaignName(c.name); }) + .catch(() => {}); }, []); const handleNext = () => setStep(prev => prev + 1); @@ -41,6 +45,7 @@ export default function Setup({ onComplete }: { onComplete: () => void }) { setSaving(true); setError(""); try { + await api.updateCampaign('default', { name: campaignName }); await api.updateCampaignSettings('default', settings); await api.updateSettings({ onboarding_completed: true }); onComplete(); @@ -112,7 +117,18 @@ export default function Setup({ onComplete }: { onComplete: () => void }) { {step === 2 && (
-

2. Summarization Engine (LLM)

+

Campaign Name

+

Give your campaign a name — you can change it later in Settings.

+ setCampaignName(e.target.value)} + placeholder="My Campaign" + className="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2 text-white" + /> +
+
+

Summarization Engine (LLM)

Choose where your post-transcription formatting and smart summaries are generated.