timeline: remove GPU, add SSE status updates, DOCX export, single-file, engine-aware credits

- Remove GPU/cuttlefish engine from timeline.php, api/timeline.php, LegalTools.php, tools.js (all 4 langs)
- Add engine-aware credit cost: gpt-4o-mini=1 credit, gpt-4o=2 credits (matches redact pattern)
- Remove multiple attribute from file input (single document only)
- New api/timeline-stream.php: SSE endpoint emitting status events + final result
- New api/timeline-download.php: DOCX export of timeline events
- LegalTools::timeline() gains ?callable $onProgress for live status updates
- tools.js: spinner on run, SSE streaming fetch, Export to Word button
- Save to My Docs was already wired (showSaveResultButton at line 1136)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 09:32:28 +02:00
parent 4b8b675a64
commit d47024ed67
7 changed files with 406 additions and 43 deletions
+2 -3
View File
@@ -27,7 +27,6 @@ require_once __DIR__ . '/includes/layout.php';
<span class="control-label" data-i18n="timelineEngine">Engine</span>
<label><input type="radio" name="timelineEngine" value="azure_mini" checked id="timelineEngineAzureMini"> <span data-i18n="timelineEngineAzureMini">Azure gpt-4o-mini</span> &#9733; <small class="control-hint">(fast)</small></label>
<label><input type="radio" name="timelineEngine" value="azure_full" id="timelineEngineAzureFull"> <span data-i18n="timelineEngineAzureFull">Azure gpt-4o</span> <small class="control-hint">(best)</small></label>
<label><input type="radio" name="timelineEngine" value="gpu" id="timelineEngineGpu"> <span data-i18n="timelineEngineGpu">GPU (cuttlefish)</span> <small class="control-hint">(local)</small></label>
</div>
<p class="upload-hint" data-i18n="timelineEngineHint">Azure engines use your BNL Azure credits. GPU runs the local LiteLLM proxy on cuttlefish.</p>
@@ -74,10 +73,10 @@ require_once __DIR__ . '/includes/layout.php';
</div>
<div class="upload-zone" id="uploadZone" role="region" aria-label="File upload" data-i18n-aria="timelineUploadAria">
<input type="file" id="uploadInput" multiple accept=".pdf,.docx,.txt" aria-label="Choose files">
<input type="file" id="uploadInput" accept=".pdf,.docx,.txt" aria-label="Choose files">
<div id="uploadPrompt" class="upload-prompt">
<span class="upload-icon" aria-hidden="true">&#8679;</span>
<p><span data-i18n="timelineUploadDrop">Drop up to 5 files here, or</span> <label for="uploadInput" class="upload-browse" data-i18n="timelineUploadBrowse">browse</label></p>
<p><span data-i18n="timelineUploadDrop">Drop a file here, or</span> <label for="uploadInput" class="upload-browse" data-i18n="timelineUploadBrowse">browse</label></p>
<p class="upload-hint"><strong>PDF</strong>, <strong>DOCX</strong>, <strong>TXT</strong> &mdash; <span data-i18n="timelineUploadHint">text extracted in memory, never stored</span></p>
</div>
<div id="uploadFileInfo" class="upload-file is-hidden">