import type { AiConversation, AiMessage } from '~/types/ai' export function useAiChat() { const client = useSupabaseClient() const user = useSupabaseUser() const conversations = ref([]) const currentConversation = ref(null) const messages = ref([]) const streamingContent = ref('') const isStreaming = ref(false) const loading = ref(false) async function fetchConversations() { if (!user.value) return const { data } = await client .from('ai_conversations') .select('*') .order('updated_at', { ascending: false }) conversations.value = (data as AiConversation[]) ?? [] } async function createConversation(title: string = '새 대화') { if (!user.value) return null const { data, error } = await client .from('ai_conversations') .insert({ user_id: user.value.id, title }) .select() .single() if (error) return null const conv = data as AiConversation conversations.value.unshift(conv) return conv } async function selectConversation(conv: AiConversation) { currentConversation.value = conv await fetchMessages(conv.id) } async function fetchMessages(conversationId: string) { const { data } = await client .from('ai_messages') .select('*') .eq('conversation_id', conversationId) .order('created_at', { ascending: true }) messages.value = (data as AiMessage[]) ?? [] } async function deleteConversation(id: string) { await client.from('ai_conversations').delete().eq('id', id) conversations.value = conversations.value.filter(c => c.id !== id) if (currentConversation.value?.id === id) { currentConversation.value = null messages.value = [] } } async function sendMessage(content: string) { if (!currentConversation.value || isStreaming.value) return // Save user message to DB const { data: userMsg } = await client .from('ai_messages') .insert({ conversation_id: currentConversation.value.id, role: 'user', content }) .select() .single() if (userMsg) messages.value.push(userMsg as AiMessage) // Start streaming isStreaming.value = true streamingContent.value = '' try { const response = await fetch('/api/ai/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ conversationId: currentConversation.value.id, messages: messages.value.map(m => ({ role: m.role, content: m.content })) }) }) if (!response.ok) throw new Error('API 오류') const reader = response.body!.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done) break streamingContent.value += decoder.decode(value, { stream: true }) } // Save assistant message to DB const finalContent = streamingContent.value const { data: assistantMsg } = await client .from('ai_messages') .insert({ conversation_id: currentConversation.value.id, role: 'assistant', content: finalContent }) .select() .single() if (assistantMsg) messages.value.push(assistantMsg as AiMessage) // Update conversation title if it's the first message if (messages.value.length === 2) { const title = content.slice(0, 30) + (content.length > 30 ? '...' : '') await client .from('ai_conversations') .update({ title }) .eq('id', currentConversation.value.id) const conv = conversations.value.find(c => c.id === currentConversation.value!.id) if (conv) conv.title = title } } catch (e) { console.error('Streaming error:', e) } finally { isStreaming.value = false streamingContent.value = '' } } return { conversations: readonly(conversations), currentConversation: readonly(currentConversation), messages: readonly(messages), streamingContent: readonly(streamingContent), isStreaming: readonly(isStreaming), loading: readonly(loading), fetchConversations, createConversation, selectConversation, deleteConversation, sendMessage } }