first implementation
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { api } from '@/services/api'
|
||||
|
||||
export interface ChatMessage {
|
||||
id: string
|
||||
role: 'USER' | 'ASSISTANT'
|
||||
content: string
|
||||
sources: Array<{ bookTitle: string; page: number | null }>
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
export interface ChatSession {
|
||||
sessionId: string
|
||||
topicId: string | null
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
export const useChatStore = defineStore('chat', () => {
|
||||
const session = ref<ChatSession | null>(null)
|
||||
const messages = ref<ChatMessage[]>([])
|
||||
const loading = ref(false)
|
||||
const sending = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
async function createSession(topicId?: string): Promise<boolean> {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const body = topicId ? { topicId } : {}
|
||||
const response = await api.post<ChatSession>('/chat/sessions', body)
|
||||
session.value = response.data
|
||||
messages.value = []
|
||||
return true
|
||||
} catch (err: any) {
|
||||
error.value = err.message
|
||||
return false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMessages(): Promise<void> {
|
||||
if (!session.value) return
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const response = await api.get<ChatMessage[]>(
|
||||
`/chat/sessions/${session.value.sessionId}/messages`
|
||||
)
|
||||
messages.value = response.data
|
||||
} catch (err: any) {
|
||||
error.value = err.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function sendMessage(content: string): Promise<boolean> {
|
||||
if (!session.value) return false
|
||||
sending.value = true
|
||||
error.value = null
|
||||
|
||||
// Optimistically add user message
|
||||
const tempUserMsg: ChatMessage = {
|
||||
id: crypto.randomUUID(),
|
||||
role: 'USER',
|
||||
content,
|
||||
sources: [],
|
||||
createdAt: new Date().toISOString()
|
||||
}
|
||||
messages.value.push(tempUserMsg)
|
||||
|
||||
try {
|
||||
const response = await api.post<ChatMessage>(
|
||||
`/chat/sessions/${session.value.sessionId}/messages`,
|
||||
{ content }
|
||||
)
|
||||
// Replace temp message & add assistant response
|
||||
messages.value = messages.value.filter((m) => m.id !== tempUserMsg.id)
|
||||
// Reload full conversation to stay in sync
|
||||
await loadMessages()
|
||||
return true
|
||||
} catch (err: any) {
|
||||
// Remove optimistic message on failure
|
||||
messages.value = messages.value.filter((m) => m.id !== tempUserMsg.id)
|
||||
error.value = err.message
|
||||
return false
|
||||
} finally {
|
||||
sending.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteSession(): Promise<boolean> {
|
||||
if (!session.value) return false
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
await api.delete(`/chat/sessions/${session.value.sessionId}`)
|
||||
session.value = null
|
||||
messages.value = []
|
||||
return true
|
||||
} catch (err: any) {
|
||||
error.value = err.message
|
||||
return false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
session,
|
||||
messages,
|
||||
loading,
|
||||
sending,
|
||||
error,
|
||||
createSession,
|
||||
loadMessages,
|
||||
sendMessage,
|
||||
deleteSession
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user