SimpleChatTCRV:iDB:Add Put/Get; SimpleChat Save/Load using iDB

Added put and get helpers wrt indexedDB.

Updated save and load related logics in SimpleChatTCRV.
This commit is contained in:
hanishkvc 2025-11-11 22:17:07 +05:30
parent 52cce3e5f7
commit 570131943f
3 changed files with 120 additions and 20 deletions

View File

@ -32,6 +32,7 @@ export function db_open(dbName, storeName, callerTag="") {
}); });
} }
/** /**
* Get hold of a transaction wrt a specified store in the db * Get hold of a transaction wrt a specified store in the db
* @param {IDBDatabase} db * @param {IDBDatabase} db
@ -43,3 +44,62 @@ export function db_trans_store(db, storeName, opMode) {
let dbOS = dbTrans.objectStore(storeName); let dbOS = dbTrans.objectStore(storeName);
return dbOS return dbOS
} }
/**
* Put a given key-value pair into a store in a db.
* Return success or failure through callback.
*
* @param {string} dbName
* @param {string} storeName
* @param {IDBValidKey} key
* @param {any} value
* @param {string | undefined} callerTag
* @param {(status: boolean, related: IDBValidKey | DOMException | null) => void} cb
*/
export function db_put(dbName, storeName, key, value, callerTag, cb) {
let tag = `iDB:Put:${callerTag}`;
db_open(dbName, storeName, tag).then((/** @type {IDBDatabase} */db)=>{
let reqPut = db_trans_store(db, storeName, 'readwrite').put(value, key)
reqPut.onerror = (evPut) => {
console.info(`ERRR:${tag}:OnError:transact failed:${reqPut.error}`)
cb(false, reqPut.error)
}
reqPut.onsuccess = (evPut) => {
console.info(`DBUG:${tag}:transact success`)
cb(true, reqPut.result)
}
}).catch((errReason)=>{
console.info(`ERRR:${tag}:Caught:transact failed:${errReason}`)
cb(false, errReason)
})
}
/**
* Return value of specified key from a store in a db,
* through the provided callback.
*
* @param {string} dbName
* @param {string} storeName
* @param {IDBValidKey} key
* @param {string | undefined} callerTag
* @param {(status: boolean, related: IDBValidKey | DOMException | null) => void} cb
*/
export function db_get(dbName, storeName, key, callerTag, cb) {
let tag = `iDB:Get:${callerTag}`;
db_open(dbName, storeName, tag).then((/** @type {IDBDatabase} */db)=>{
let reqGet = db_trans_store(db, storeName, 'readonly').get(key);
reqGet.onsuccess = (evGet) => {
console.info(`DBUG:${tag}:transact success`)
cb(true, reqGet.result)
}
reqGet.onerror = (evGet) => {
console.info(`ERRR:${tag}:OnError:transact failed:${reqGet.error}`)
cb(false, reqGet.error)
}
}).catch((errReason)=>{
console.info(`ERRR:${tag}:Caught:transact failed:${errReason}`)
cb(false, errReason)
})
}

View File

@ -734,6 +734,11 @@ sliding window based drop off or even before they kick in, this can help in many
* SimpleChat class now allows extra fields to be specified while adding, in a generic way using a * SimpleChat class now allows extra fields to be specified while adding, in a generic way using a
object/literal object or equivalent. object/literal object or equivalent.
* UI Cleanup - msgs spaced out, toolcall edit hr not always, scroll ui only when required,
hide settings/info till user requests, heading gradient
* iDB module - add open, transact, put and get. Use for chat session save and load
#### ToDo #### ToDo

View File

@ -6,6 +6,11 @@
import * as du from "./datautils.mjs"; import * as du from "./datautils.mjs";
import * as ui from "./ui.mjs" import * as ui from "./ui.mjs"
import * as mTools from "./tools.mjs" import * as mTools from "./tools.mjs"
import * as mIdb from "./idb.mjs"
const DB_NAME = "SimpleChatTCRV"
const DB_STORE = "Sessions"
const ROLES_TEMP_ENDSWITH = ".TEMP" const ROLES_TEMP_ENDSWITH = ".TEMP"
@ -468,29 +473,48 @@ class SimpleChat {
} }
/** /**
* Save into localStorage * Save into indexedDB
*/ */
save() { save() {
let tag = `SimpleChat:Save:${this.chatId}`;
/** @type {SimpleChatODS} */ /** @type {SimpleChatODS} */
let ods = {iLastSys: this.iLastSys, xchat: this.xchat}; let ods = {iLastSys: this.iLastSys, xchat: this.xchat};
localStorage.setItem(this.ods_key(), JSON.stringify(ods)); mIdb.db_put(DB_NAME, DB_STORE, this.ods_key(), JSON.stringify(ods), tag, (status, related)=>{
console.log(`DBUG:${tag}:${status}:${related}`)
if (!status) {
throw new Error(`ERRR:${tag}:${related}`)
}
})
} }
/** /**
* Load from localStorage * Load from indexedDB, get status through callback.
* @param {((loadStatus: boolean, dbStatus: boolean, related: IDBValidKey | DOMException | null) => void)} cb
*/ */
load() { load(cb) {
let sods = localStorage.getItem(this.ods_key()); let tag = `SimpleChat:Load:${this.chatId}`;
if (sods == null) { mIdb.db_get(DB_NAME, DB_STORE, this.ods_key(), tag, (status, related)=>{
return; if (!status) {
} cb(false, status, `ERRR:${tag}:Db failure:${related}`);
/** @type {SimpleChatODS} */ return
let ods = JSON.parse(sods); }
this.iLastSys = ods.iLastSys; if (!related) {
this.xchat = []; cb(false, status, `ERRR:${tag}:No data?`);
for (const cur of ods.xchat) { return
this.xchat.push(new ChatMessageEx(new NSChatMessage(cur.ns.role, cur.ns.content, cur.ns.reasoning_content, cur.ns.tool_calls, cur.ns.tool_call_id, cur.ns.name, cur.ns.image_url), cur.trimmedContent)) }
} if (typeof(related) == "string") {
/** @type {SimpleChatODS} */
let ods = JSON.parse(related);
this.iLastSys = ods.iLastSys;
this.xchat = [];
for (const cur of ods.xchat) {
this.xchat.push(new ChatMessageEx(new NSChatMessage(cur.ns.role, cur.ns.content, cur.ns.reasoning_content, cur.ns.tool_calls, cur.ns.tool_call_id, cur.ns.name, cur.ns.image_url), cur.trimmedContent))
}
cb(true, status, related)
} else {
cb(false, status, `ERRR:${tag}:DOMException?:${related}`);
}
})
} }
/** /**
@ -587,6 +611,10 @@ class SimpleChat {
* *
* NOTE: A new copy is created and added into xchat. * NOTE: A new copy is created and added into xchat.
* Also update iLastSys system prompt index tracker * Also update iLastSys system prompt index tracker
*
* ALERT: Also triggers a save, which occurs assynchronously in the background, as of now,
* with no handle returned wrt same.
*
* @param {ChatMessageEx} chatMsg * @param {ChatMessageEx} chatMsg
* @param {Object<string,any>|undefined} extra - optional additional fieldName=Value pairs to be added, if any * @param {Object<string,any>|undefined} extra - optional additional fieldName=Value pairs to be added, if any
*/ */
@ -1652,11 +1680,18 @@ export class Me {
div.innerHTML += `<p class="role-system">Restore</p> div.innerHTML += `<p class="role-system">Restore</p>
<p>Load previously saved chat session, if available</p>`; <p>Load previously saved chat session, if available</p>`;
let btn = ui.el_create_button(chat.ods_key(), (ev)=>{ let btn = ui.el_create_button(chat.ods_key(), (ev)=>{
console.log("DBUG:SimpleChat:SC:Load", chat); let tag = `Me:Load:${chat.chatId}`;
chat.load(); console.log(`DBUG:${tag}`, chat);
queueMicrotask(()=>{ chat.load((loadStatus, dbStatus, related)=>{
this.multiChat.chat_show(chat.chatId, true, true); if (!loadStatus || !dbStatus) {
this.multiChat.elInSystem.value = chat.get_system_latest().ns.getContent(); console.log(`WARN:${tag}:DidntLoad:${loadStatus}:${dbStatus}:${related}`);
return;
}
console.log(`INFO:${tag}:Loaded:${loadStatus}:${dbStatus}`);
queueMicrotask(()=>{
this.multiChat.chat_show(chat.chatId, true, true);
this.multiChat.elInSystem.value = chat.get_system_latest().ns.getContent();
});
}); });
}); });
div.appendChild(btn); div.appendChild(btn);