add new concept report

This commit is contained in:
Adrien
2026-04-18 17:54:54 +02:00
parent 5f03e1f41b
commit c7a77af2f4
29 changed files with 1892 additions and 41 deletions
+68 -2
View File
@@ -32,6 +32,13 @@
<span>{{ book.status === 'PENDING' ? 'Queued for processing...' : 'Embedding in progress...' }}</span>
</div>
<div v-if="enrichProgress && enrichProgress.status === 'RUNNING'" class="processing-indicator">
<div class="spinner spinner-dark"></div>
<span>Enriching chunks {{ enrichProgress.chunksEnriched }} / {{ enrichProgress.chunksTotal }}</span>
</div>
<div v-if="enrichFeedback" class="enrich-feedback">{{ enrichFeedback }}</div>
<div class="book-actions">
<router-link
v-if="book.status === 'READY'"
@@ -40,6 +47,15 @@
>
Read
</router-link>
<button
v-if="book.status === 'READY'"
class="btn btn-secondary"
:disabled="enrichRunning"
@click="handleEnrich"
title="Enrich chunks with concept metadata"
>
{{ enrichRunning ? 'Enriching...' : 'Enrich' }}
</button>
<button
v-if="deleteEnabled"
class="btn btn-danger"
@@ -54,8 +70,9 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { Book } from '@/stores/bookStore'
import { computed, onUnmounted, ref } from 'vue'
import type { Book, EnrichmentProgress } from '@/stores/bookStore'
import { useBookStore } from '@/stores/bookStore'
const props = defineProps<{
book: Book
@@ -67,6 +84,46 @@ defineEmits<{
(e: 'delete', id: string): void
}>()
const bookStore = useBookStore()
const enrichProgress = ref<EnrichmentProgress | null>(null)
const enrichFeedback = ref<string | null>(null)
let pollTimer: ReturnType<typeof setInterval> | null = null
const enrichRunning = computed(() => enrichProgress.value?.status === 'RUNNING')
async function handleEnrich() {
enrichFeedback.value = null
const started = await bookStore.startEnrichment(props.book.id)
if (!started) {
enrichFeedback.value = bookStore.error ?? 'Enrichment failed to start.'
return
}
enrichProgress.value = started
startPolling()
}
function startPolling() {
stopPolling()
pollTimer = setInterval(async () => {
const status = await bookStore.fetchEnrichmentStatus(props.book.id)
if (!status) return
enrichProgress.value = status
if (status.status === 'COMPLETED') {
stopPolling()
enrichFeedback.value = `Enriched ${status.chunksEnriched} / ${status.chunksTotal} chunks.`
}
}, 2000)
}
function stopPolling() {
if (pollTimer != null) {
clearInterval(pollTimer)
pollTimer = null
}
}
onUnmounted(stopPolling)
const statusClass = computed(() => {
switch (props.book.status) {
case 'READY':
@@ -193,4 +250,13 @@ function formatDate(iso: string): string {
gap: 0.5rem;
margin-top: 0.25rem;
}
.enrich-feedback {
font-size: 0.8rem;
color: #22543d;
background: #f0fff4;
border: 1px solid #c6f6d5;
border-radius: 6px;
padding: 0.4rem 0.6rem;
}
</style>