feat: Add transcript engine API and connect ConversationHistory to real data
- Add transcript-engine service that parses Claude Code JSONL transcripts with session listing, message extraction, token/stats analysis, and caching - Add transcript REST routes (sessions list, latest, by session ID, section filtering) - Rewrite ConversationHistory to fetch from /api/transcript/* instead of mock data - Add session pills for switching between conversation sessions - Add stats bar footer with model, duration, tokens, and tool count - Add TranscriptSession/TranscriptMessage types, ChatInput, InputSettings, PromptBar updates, TranscriptCard, and useVoiceCapture composable
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
|
||||
import type { Agent } from '../../types/agent'
|
||||
import { useVoiceCapture } from '../../composables/useVoiceCapture'
|
||||
import { useCanvasStore } from '../../stores/canvas'
|
||||
import ChatInput from './ChatInput.vue'
|
||||
import TranscriptCard from './TranscriptCard.vue'
|
||||
import InputSettings from './InputSettings.vue'
|
||||
import ConversationHistory from './ConversationHistory.vue'
|
||||
|
||||
interface ChatMessage {
|
||||
@@ -35,11 +38,17 @@ const emit = defineEmits<{
|
||||
submit: [text: string]
|
||||
}>()
|
||||
|
||||
const canvasStore = useCanvasStore()
|
||||
const voice = useVoiceCapture({
|
||||
onNotification: (msg, type, duration) => canvasStore.showNotification(msg, type, duration)
|
||||
})
|
||||
|
||||
const contentEl = ref<HTMLDivElement | null>(null)
|
||||
const chatInputEl = ref<InstanceType<typeof ChatInput> | null>(null)
|
||||
const isRecording = ref(false)
|
||||
const showTranscript = ref(false)
|
||||
const showHistory = ref(false)
|
||||
const showSettings = ref(false)
|
||||
const messages = reactive<ChatMessage[]>([])
|
||||
|
||||
const panelStyle = computed(() => {
|
||||
@@ -60,7 +69,7 @@ const panelStyle = computed(() => {
|
||||
})
|
||||
|
||||
const hasContent = computed(() =>
|
||||
messages.length > 0 || showTranscript.value || showHistory.value
|
||||
messages.length > 0 || showTranscript.value || showHistory.value || showSettings.value
|
||||
)
|
||||
|
||||
async function scrollToBottom() {
|
||||
@@ -100,6 +109,8 @@ function handleTranscriptDone(text: string) {
|
||||
isRecording.value = false
|
||||
showTranscript.value = false
|
||||
|
||||
if (!text.trim()) return
|
||||
|
||||
messages.push({ id: ++idCounter, role: 'user', content: text, status: 'sent' })
|
||||
|
||||
const agentMsg: ChatMessage = { id: ++idCounter, role: 'agent', content: '', status: 'thinking' }
|
||||
@@ -108,6 +119,10 @@ function handleTranscriptDone(text: string) {
|
||||
pushAgentResponse(agentMsg)
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
showSettings.value = !showSettings.value
|
||||
}
|
||||
|
||||
function toggleHistory() {
|
||||
showHistory.value = !showHistory.value
|
||||
if (showHistory.value) scrollToBottom()
|
||||
@@ -122,14 +137,22 @@ watch(() => props.visible, async (v) => {
|
||||
isRecording.value = false
|
||||
showTranscript.value = false
|
||||
showHistory.value = false
|
||||
showSettings.value = false
|
||||
messages.length = 0
|
||||
idCounter = 0
|
||||
await voice.init()
|
||||
await nextTick()
|
||||
if (props.startRecording) {
|
||||
handleMic()
|
||||
} else {
|
||||
chatInputEl.value?.focus()
|
||||
}
|
||||
} else {
|
||||
// Cleanup when panel closes
|
||||
if (voice.isRecording.value) {
|
||||
voice.stopRecording()
|
||||
}
|
||||
voice.cleanup()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -142,6 +165,7 @@ onMounted(() => {
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('keydown', handleKeydown)
|
||||
if (thinkTimer) clearTimeout(thinkTimer)
|
||||
voice.cleanup()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -187,7 +211,8 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<TranscriptCard v-if="showTranscript" @done="handleTranscriptDone" />
|
||||
<TranscriptCard v-if="showTranscript" :voice="voice" @done="handleTranscriptDone" />
|
||||
<InputSettings v-if="showSettings" :voice="voice" @close="showSettings = false" />
|
||||
<ConversationHistory v-if="showHistory" :agent="agent" />
|
||||
</div>
|
||||
|
||||
@@ -197,10 +222,12 @@ onBeforeUnmount(() => {
|
||||
:placeholder="`Mensaje a ${agent.uiConfig?.label || agent.name}...`"
|
||||
:recording="isRecording"
|
||||
:history-active="showHistory"
|
||||
:settings-active="showSettings"
|
||||
:autofocus="visible"
|
||||
@submit="handleSubmit"
|
||||
@mic="handleMic"
|
||||
@toggle-history="toggleHistory"
|
||||
@toggle-settings="toggleSettings"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user