Template
Initial ChatGPT Agent demo
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
import type { UIMessage } from 'ai';
|
||||
|
||||
const DATABASE_NAME = 'chatgpt-agent-demo';
|
||||
const DATABASE_VERSION = 1;
|
||||
const CHATS_STORE = 'chats';
|
||||
const MESSAGES_STORE = 'messages';
|
||||
|
||||
export interface StoredChat {
|
||||
id: string;
|
||||
title: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface StoredMessages {
|
||||
chatId: string;
|
||||
messages: UIMessage[];
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
let databasePromise: Promise<IDBDatabase> | null = null;
|
||||
|
||||
function openDatabase(): Promise<IDBDatabase> {
|
||||
if (typeof window === 'undefined' || !('indexedDB' in window)) {
|
||||
return Promise.reject(new Error('IndexedDB is not available'));
|
||||
}
|
||||
|
||||
if (databasePromise) return databasePromise;
|
||||
|
||||
databasePromise = new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
|
||||
|
||||
request.onupgradeneeded = () => {
|
||||
const database = request.result;
|
||||
|
||||
if (!database.objectStoreNames.contains(CHATS_STORE)) {
|
||||
database.createObjectStore(CHATS_STORE, { keyPath: 'id' });
|
||||
}
|
||||
|
||||
if (!database.objectStoreNames.contains(MESSAGES_STORE)) {
|
||||
database.createObjectStore(MESSAGES_STORE, { keyPath: 'chatId' });
|
||||
}
|
||||
};
|
||||
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onblocked = () =>
|
||||
reject(new Error('IndexedDB upgrade was blocked by another tab'));
|
||||
});
|
||||
|
||||
return databasePromise;
|
||||
}
|
||||
|
||||
function requestToPromise<T>(request: IDBRequest<T>): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
function transactionToPromise(transaction: IDBTransaction): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
transaction.oncomplete = () => resolve();
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
transaction.onabort = () =>
|
||||
reject(transaction.error ?? new Error('IndexedDB transaction aborted'));
|
||||
});
|
||||
}
|
||||
|
||||
export async function createChat(id: string, title: string): Promise<StoredChat> {
|
||||
const database = await openDatabase();
|
||||
const now = new Date().toISOString();
|
||||
const chat: StoredChat = {
|
||||
id,
|
||||
title,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
};
|
||||
const transaction = database.transaction(CHATS_STORE, 'readwrite');
|
||||
transaction.objectStore(CHATS_STORE).put(chat);
|
||||
await transactionToPromise(transaction);
|
||||
return chat;
|
||||
}
|
||||
|
||||
export async function listChats(): Promise<StoredChat[]> {
|
||||
const database = await openDatabase();
|
||||
const transaction = database.transaction(CHATS_STORE, 'readonly');
|
||||
const chats = await requestToPromise(
|
||||
transaction.objectStore(CHATS_STORE).getAll() as IDBRequest<StoredChat[]>
|
||||
);
|
||||
|
||||
return chats.sort((a, b) => b.updated_at.localeCompare(a.updated_at));
|
||||
}
|
||||
|
||||
export async function getMessages(chatId: string): Promise<UIMessage[]> {
|
||||
const database = await openDatabase();
|
||||
const transaction = database.transaction(MESSAGES_STORE, 'readonly');
|
||||
const record = await requestToPromise(
|
||||
transaction.objectStore(MESSAGES_STORE).get(chatId) as IDBRequest<
|
||||
StoredMessages | undefined
|
||||
>
|
||||
);
|
||||
|
||||
return record?.messages ?? [];
|
||||
}
|
||||
|
||||
export async function saveMessages(
|
||||
chatId: string,
|
||||
messages: UIMessage[]
|
||||
): Promise<void> {
|
||||
const database = await openDatabase();
|
||||
const now = new Date().toISOString();
|
||||
const transaction = database.transaction(
|
||||
[CHATS_STORE, MESSAGES_STORE],
|
||||
'readwrite'
|
||||
);
|
||||
const chatsStore = transaction.objectStore(CHATS_STORE);
|
||||
|
||||
const chatRequest = chatsStore.get(chatId) as IDBRequest<
|
||||
StoredChat | undefined
|
||||
>;
|
||||
chatRequest.onsuccess = () => {
|
||||
if (chatRequest.result) {
|
||||
chatsStore.put({ ...chatRequest.result, updated_at: now });
|
||||
}
|
||||
};
|
||||
|
||||
transaction.objectStore(MESSAGES_STORE).put({
|
||||
chatId,
|
||||
messages,
|
||||
updated_at: now,
|
||||
} satisfies StoredMessages);
|
||||
|
||||
await transactionToPromise(transaction);
|
||||
}
|
||||
|
||||
export async function deleteChat(chatId: string): Promise<void> {
|
||||
const database = await openDatabase();
|
||||
const transaction = database.transaction(
|
||||
[CHATS_STORE, MESSAGES_STORE],
|
||||
'readwrite'
|
||||
);
|
||||
transaction.objectStore(CHATS_STORE).delete(chatId);
|
||||
transaction.objectStore(MESSAGES_STORE).delete(chatId);
|
||||
await transactionToPromise(transaction);
|
||||
}
|
||||
Reference in New Issue
Block a user