92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
import { createClient } from "@/lib/supabase/client"
|
|
|
|
export type AIConversation = {
|
|
id: string
|
|
knowledge_item_id: string | null
|
|
title: string | null
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export type AIMessageRow = {
|
|
id: string
|
|
conversation_id: string
|
|
role: "user" | "assistant" | "system"
|
|
content: string
|
|
created_at: string
|
|
}
|
|
|
|
/** Get the latest conversation for a knowledge item, if any. */
|
|
export async function getLatestConversation(knowledgeItemId: string): Promise<AIConversation | null> {
|
|
const supabase = createClient()
|
|
const { data, error } = await supabase
|
|
.from("ai_conversations")
|
|
.select("*")
|
|
.eq("knowledge_item_id", knowledgeItemId)
|
|
.order("updated_at", { ascending: false })
|
|
.limit(1)
|
|
.maybeSingle()
|
|
if (error) throw error
|
|
return (data as AIConversation) ?? null
|
|
}
|
|
|
|
export async function createConversation(knowledgeItemId: string, title: string): Promise<AIConversation> {
|
|
const supabase = createClient()
|
|
const { data, error } = await supabase
|
|
.from("ai_conversations")
|
|
.insert({ knowledge_item_id: knowledgeItemId, title })
|
|
.select("*")
|
|
.single()
|
|
if (error) throw error
|
|
return data as AIConversation
|
|
}
|
|
|
|
export async function fetchMessages(conversationId: string): Promise<AIMessageRow[]> {
|
|
const supabase = createClient()
|
|
const { data, error } = await supabase
|
|
.from("ai_messages")
|
|
.select("*")
|
|
.eq("conversation_id", conversationId)
|
|
.order("created_at", { ascending: true })
|
|
if (error) throw error
|
|
return (data ?? []) as AIMessageRow[]
|
|
}
|
|
|
|
export async function addMessage(
|
|
conversationId: string,
|
|
role: "user" | "assistant",
|
|
content: string,
|
|
): Promise<AIMessageRow> {
|
|
const supabase = createClient()
|
|
const { data, error } = await supabase
|
|
.from("ai_messages")
|
|
.insert({ conversation_id: conversationId, role, content })
|
|
.select("*")
|
|
.single()
|
|
if (error) throw error
|
|
// touch conversation updated_at
|
|
await supabase.from("ai_conversations").update({ updated_at: new Date().toISOString() }).eq("id", conversationId)
|
|
return data as AIMessageRow
|
|
}
|
|
|
|
export async function clearMessages(conversationId: string): Promise<void> {
|
|
const supabase = createClient()
|
|
const { error } = await supabase.from("ai_messages").delete().eq("conversation_id", conversationId)
|
|
if (error) throw error
|
|
}
|
|
|
|
export async function deleteLastAssistantMessage(conversationId: string): Promise<void> {
|
|
const supabase = createClient()
|
|
const { data, error } = await supabase
|
|
.from("ai_messages")
|
|
.select("id, role")
|
|
.eq("conversation_id", conversationId)
|
|
.order("created_at", { ascending: false })
|
|
.limit(1)
|
|
.maybeSingle()
|
|
if (error) throw error
|
|
if (data && (data as { role: string }).role === "assistant") {
|
|
await supabase.from("ai_messages").delete().eq("id", (data as { id: string }).id)
|
|
}
|
|
}
|