feat: document & audio corpus picker for all tools
- Add "Select from My Docs" button to all text tool forms; free-tier users see an upgrade modal, paid (CaveauAI) users get a searchable multi-select modal backed by /api/dashboard/documents.php - Add "Select from My Audio" picker on Transcribe with single-select and a "Save to My Audio" button for persisting uploaded clips - New PHP helpers in bootstrap.php: dbnToolsFetchDocChunks, dbnToolsClientIdFromSession, dbnToolsInjectDocContent - timeline, ask, redact APIs prepend selected document content (fetched from client_chunks SQL) before the textarea text - api/dashboard/audio-upload.php stores audio files on server and creates a client_documents row with source_type='audio' - api/transcribe.php falls back to stored audio via audio_doc_id POST field when no file is uploaded - api/dashboard/documents.php supports ?source_type= filter - tools.js: doc_ids added to JSON payload; stored-audio transcribe path - New assets/css/doc-picker.css, assets/js/doc-picker.js - SQL migration: scripts/sql/audio_docs_column.sql Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+46
-3
@@ -1070,13 +1070,17 @@ async function runTool(event) {
|
||||
|
||||
const tool = tools[state.activeTool];
|
||||
const text = els.input.value.trim();
|
||||
if (!text) {
|
||||
els.status.textContent = 'Add text before running the tool.';
|
||||
els.input.focus();
|
||||
const docIds = (document.getElementById('docPickerIds')?.value || '')
|
||||
.split(',').map(Number).filter(Boolean);
|
||||
|
||||
if (!text && !docIds.length) {
|
||||
els.status.textContent = 'Add text or select a document before running the tool.';
|
||||
if (!docIds.length) els.input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = { [tool.payloadKey]: text };
|
||||
if (docIds.length) payload.doc_ids = docIds;
|
||||
if (tool.usesLanguage) {
|
||||
payload.language = currentLanguage();
|
||||
}
|
||||
@@ -1812,6 +1816,45 @@ function showTranscribeProgress(clip, total) {
|
||||
}
|
||||
|
||||
async function runTranscribe() {
|
||||
const storedAudioDocId = parseInt(document.getElementById('audioPickerDocId')?.value || '0', 10);
|
||||
|
||||
// Stored audio path — no file in the queue required
|
||||
if (storedAudioDocId > 0 && !audioQueue.length) {
|
||||
setBusy(true);
|
||||
els.status.textContent = 'Transcribing from corpus…';
|
||||
try {
|
||||
const fd = new FormData();
|
||||
fd.append('audio_doc_id', String(storedAudioDocId));
|
||||
fd.append('language', currentTranscribeLang ? currentTranscribeLang() : 'auto');
|
||||
fd.append('task', currentTask ? currentTask() : 'transcribe');
|
||||
const vadFilter = document.getElementById('vadFilterCheck')?.checked ?? false;
|
||||
if (vadFilter) fd.append('vad_filter', '1');
|
||||
const initPrompt = (document.getElementById('initPromptInput')?.value || '').trim();
|
||||
if (initPrompt) fd.append('initial_prompt', initPrompt);
|
||||
const whisperModel = document.getElementById('whisperModelSelect')?.value;
|
||||
if (whisperModel) fd.append('model', whisperModel);
|
||||
const postModel = document.querySelector('input[name="post_model"]:checked')?.value;
|
||||
if (postModel) fd.append('post_model', postModel);
|
||||
const diarize = document.getElementById('diarizeCheck')?.checked ?? false;
|
||||
if (diarize) {
|
||||
fd.append('diarize', '1');
|
||||
const ns = parseInt(document.getElementById('numSpeakersInput')?.value || '', 10);
|
||||
if (ns >= 2) fd.append('num_speakers', String(ns));
|
||||
}
|
||||
const resp = await fetch('api/transcribe.php', { method: 'POST', credentials: 'same-origin', body: fd });
|
||||
const data = await resp.json().catch(() => ({}));
|
||||
if (!resp.ok || !data.ok) throw new Error(data.error?.message || 'Transcription failed.');
|
||||
if (typeof renderTranscribeResult === 'function') renderTranscribeResult(data);
|
||||
else renderResults(data);
|
||||
els.status.textContent = 'Done.';
|
||||
} catch (err) {
|
||||
els.status.textContent = err.message;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!audioQueue.length) {
|
||||
els.status.textContent = currentUiT('noFileSelected');
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user