Chunk/ChunkingOptions types, rechunkAnalysis API, store actions (currentChunks, rechunk), ChunkPanel UI, Prepare tab in StudioPage gated by chunking feature flag, i18n keys (FR/EN), and tests.
163 lines
4.6 KiB
TypeScript
163 lines
4.6 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import type { Analysis, Chunk, ChunkingOptions, Page, PipelineOptions } from '../../shared/types'
|
|
import * as api from './api'
|
|
|
|
export const useAnalysisStore = defineStore('analysis', () => {
|
|
const analyses = ref<Analysis[]>([])
|
|
const currentAnalysis = ref<Analysis | null>(null)
|
|
const running = ref(false)
|
|
const error = ref<string | null>(null)
|
|
const pollingInterval = ref<ReturnType<typeof setInterval> | null>(null)
|
|
const pollingTimeout = ref<ReturnType<typeof setTimeout> | null>(null)
|
|
const MAX_POLLING_DURATION = 10 * 60 * 1000 // 10 minutes
|
|
|
|
const currentPages = computed<Page[]>(() => {
|
|
if (!currentAnalysis.value?.pagesJson) return []
|
|
try {
|
|
return JSON.parse(currentAnalysis.value.pagesJson) as Page[]
|
|
} catch {
|
|
return []
|
|
}
|
|
})
|
|
|
|
function clearError(): void {
|
|
error.value = null
|
|
}
|
|
|
|
async function load(): Promise<void> {
|
|
try {
|
|
error.value = null
|
|
analyses.value = await api.fetchAnalyses()
|
|
} catch (e) {
|
|
error.value = (e as Error).message || 'Failed to load analyses'
|
|
console.error('Failed to load analyses', e)
|
|
}
|
|
}
|
|
|
|
const currentChunks = computed<Chunk[]>(() => {
|
|
if (!currentAnalysis.value?.chunksJson) return []
|
|
try {
|
|
return JSON.parse(currentAnalysis.value.chunksJson) as Chunk[]
|
|
} catch {
|
|
return []
|
|
}
|
|
})
|
|
|
|
const rechunking = ref(false)
|
|
|
|
async function rechunk(jobId: string, chunkingOptions: ChunkingOptions): Promise<Chunk[]> {
|
|
rechunking.value = true
|
|
error.value = null
|
|
try {
|
|
const chunks = await api.rechunkAnalysis(jobId, chunkingOptions)
|
|
if (currentAnalysis.value?.id === jobId) {
|
|
currentAnalysis.value = await api.fetchAnalysis(jobId)
|
|
}
|
|
return chunks
|
|
} catch (e) {
|
|
error.value = (e as Error).message || 'Failed to rechunk'
|
|
console.error('Failed to rechunk', e)
|
|
throw e
|
|
} finally {
|
|
rechunking.value = false
|
|
}
|
|
}
|
|
|
|
async function run(
|
|
documentId: string,
|
|
pipelineOptions: PipelineOptions | null = null,
|
|
chunkingOptions: ChunkingOptions | null = null,
|
|
): Promise<Analysis> {
|
|
running.value = true
|
|
error.value = null
|
|
try {
|
|
const analysis = await api.createAnalysis(documentId, pipelineOptions, chunkingOptions)
|
|
currentAnalysis.value = analysis
|
|
analyses.value.unshift(analysis)
|
|
startPolling(analysis.id)
|
|
return analysis
|
|
} catch (e) {
|
|
running.value = false
|
|
error.value = (e as Error).message || 'Failed to start analysis'
|
|
console.error('Failed to start analysis', e)
|
|
throw e
|
|
}
|
|
}
|
|
|
|
function startPolling(id: string): void {
|
|
stopPolling()
|
|
pollingInterval.value = setInterval(async () => {
|
|
try {
|
|
const updated = await api.fetchAnalysis(id)
|
|
currentAnalysis.value = updated
|
|
const idx = analyses.value.findIndex((a) => a.id === id)
|
|
if (idx !== -1) analyses.value[idx] = updated
|
|
if (updated.status === 'COMPLETED' || updated.status === 'FAILED') {
|
|
stopPolling()
|
|
running.value = false
|
|
}
|
|
} catch (e) {
|
|
error.value = (e as Error).message || 'Polling error'
|
|
console.error('Polling error', e)
|
|
stopPolling()
|
|
running.value = false
|
|
}
|
|
}, 2000)
|
|
pollingTimeout.value = setTimeout(() => {
|
|
if (pollingInterval.value) {
|
|
error.value = 'Analysis timed out'
|
|
stopPolling()
|
|
running.value = false
|
|
}
|
|
}, MAX_POLLING_DURATION)
|
|
}
|
|
|
|
function stopPolling(): void {
|
|
if (pollingInterval.value) {
|
|
clearInterval(pollingInterval.value)
|
|
pollingInterval.value = null
|
|
}
|
|
if (pollingTimeout.value) {
|
|
clearTimeout(pollingTimeout.value)
|
|
pollingTimeout.value = null
|
|
}
|
|
}
|
|
|
|
async function select(id: string): Promise<void> {
|
|
try {
|
|
currentAnalysis.value = await api.fetchAnalysis(id)
|
|
} catch (e) {
|
|
error.value = (e as Error).message || 'Failed to load analysis'
|
|
console.error('Failed to load analysis', e)
|
|
}
|
|
}
|
|
|
|
async function remove(id: string): Promise<void> {
|
|
try {
|
|
await api.deleteAnalysis(id)
|
|
analyses.value = analyses.value.filter((a) => a.id !== id)
|
|
if (currentAnalysis.value?.id === id) currentAnalysis.value = null
|
|
} catch (e) {
|
|
error.value = (e as Error).message || 'Failed to delete analysis'
|
|
console.error('Failed to delete analysis', e)
|
|
}
|
|
}
|
|
|
|
return {
|
|
analyses,
|
|
currentAnalysis,
|
|
currentPages,
|
|
currentChunks,
|
|
running,
|
|
rechunking,
|
|
error,
|
|
clearError,
|
|
load,
|
|
run,
|
|
rechunk,
|
|
select,
|
|
remove,
|
|
stopPolling,
|
|
}
|
|
})
|