Spaces:
Sleeping
Sleeping
File size: 6,164 Bytes
7e92e00 f71d0a0 7e92e00 f71d0a0 7e92e00 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import { supabase } from "@/lib/supabase";
import type { Conversation, Message, ModelId, Project } from "@/types";
const time = (value: string | number | null | undefined) => value ? new Date(value).getTime() : Date.now();
export async function loadCloudWorkspace(): Promise<{ projects: Project[]; conversations: Conversation[] }> {
const [{ data: projects, error: projectError }, { data: conversations, error: conversationError }] = await Promise.all([
supabase.from("projects").select("*").order("is_pinned", { ascending: false }).order("updated_at", { ascending: false }),
supabase.from("conversations").select("*").order("is_pinned", { ascending: false }).order("updated_at", { ascending: false }),
]);
if (projectError || conversationError) throw projectError || conversationError;
const ids = (conversations || []).map((conversation) => conversation.id);
const { data: messages, error: messageError } = ids.length
? await supabase.from("messages").select("*,message_reactions(emoji,user_id)").in("conversation_id", ids).order("created_at")
: { data: [], error: null };
if (messageError) throw messageError;
const mappedMessages = new Map<string, Message[]>();
(messages || []).forEach((message: any) => {
const reactions: Record<string, string[]> = {};
(message.message_reactions || []).forEach((reaction: any) => {
reactions[reaction.emoji] = [...(reactions[reaction.emoji] || []), reaction.user_id];
});
const item: Message = {
id: message.id, role: message.role, content: message.content, thinking: message.thinking || undefined,
thinkingTimeSeconds: message.thinking_seconds || undefined, tokens: message.token_count || undefined,
ragSources: message.rag_sources || [], authorId: message.author_id || undefined,
reactions, createdAt: time(message.created_at),
};
mappedMessages.set(message.conversation_id, [...(mappedMessages.get(message.conversation_id) || []), item]);
});
return {
projects: (projects || []).map((project: any) => ({
id: project.id, name: project.name, description: project.description,
isPinned: project.is_pinned, createdAt: time(project.created_at), updatedAt: time(project.updated_at),
})),
conversations: (conversations || []).map((conversation: any) => ({
id: conversation.id, title: conversation.title, modelId: conversation.model_id as ModelId,
projectId: conversation.project_id, isPinned: conversation.is_pinned, isGroup: conversation.is_group,
summary: conversation.compact_summary, messages: mappedMessages.get(conversation.id) || [],
createdAt: time(conversation.created_at), updatedAt: time(conversation.updated_at),
})),
};
}
export async function createCloudConversation(modelId: ModelId, projectId: string | null = null, isGroup = false) {
const { data, error } = await supabase.rpc("create_conversation_with_owner", {
title_input: "New Session", model_input: "purcar", project_input: projectId, group_input: isGroup,
});
if (error) throw error;
return data as string;
}
export async function saveCloudMessage(conversationId: string, message: Message) {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error("Sign in required");
const { error } = await supabase.from("messages").upsert({
id: message.id, conversation_id: conversationId, author_id: user.id, role: message.role,
content: message.content, thinking: message.thinking || null, thinking_seconds: message.thinkingTimeSeconds || null,
token_count: message.tokens || null, rag_sources: message.ragSources || [], created_at: new Date(message.createdAt).toISOString(),
});
if (error) throw error;
}
export async function updateCloudConversation(id: string, patch: Record<string, unknown>) {
const { error } = await supabase.from("conversations").update({ ...patch, updated_at: new Date().toISOString() }).eq("id", id);
if (error) throw error;
}
export async function deleteCloudConversation(id: string) {
const { error } = await supabase.from("conversations").delete().eq("id", id);
if (error) throw error;
}
export async function createCloudProject(name: string) {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error("Sign in required");
const { data, error } = await supabase.from("projects").insert({ owner_id: user.id, name: name.trim() }).select("*").single();
if (error) throw error;
return { id: data.id, name: data.name, description: data.description, isPinned: data.is_pinned, createdAt: time(data.created_at), updatedAt: time(data.updated_at) } as Project;
}
export async function inviteCloudMember(conversationId: string, username: string) {
const { error } = await supabase.rpc("invite_conversation_member", { conversation_input: conversationId, username_input: username.replace(/^@/, "").trim() });
if (error) throw error;
}
export type ConversationInvite = {
id: string; conversationId: string; conversationTitle: string; inviterId: string; status: string; createdAt: string;
};
export async function loadPendingConversationInvites(): Promise<ConversationInvite[]> {
const { data, error } = await supabase.rpc("get_pending_conversation_invites");
if (error) throw error;
return (data || []).map((item: any) => ({ id: item.id, conversationId: item.conversation_id, conversationTitle: item.conversation_title, inviterId: item.inviter_id, status: item.status, createdAt: item.created_at }));
}
export async function respondToConversationInvite(id: string, accept: boolean): Promise<string> {
const { data, error } = await supabase.rpc("respond_to_conversation_invite", { invitation_input: id, accept_input: accept });
if (error) throw error;
return data as string;
}
export async function toggleCloudReaction(messageId: string, emoji: string, userId: string, active: boolean) {
const query = supabase.from("message_reactions");
const { error } = active
? await query.delete().eq("message_id", messageId).eq("user_id", userId).eq("emoji", emoji)
: await query.insert({ message_id: messageId, user_id: userId, emoji });
if (error) throw error;
}
|