add new concept report
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user