parent
6d53e108d0
commit
83b8544404
3 changed files with 156 additions and 52 deletions
|
|
@ -28,6 +28,9 @@ export class taStorage {
|
|||
|
||||
taLog = null;
|
||||
|
||||
/**
|
||||
* @param {boolean} [do_debug=false] - Enable debug logging.
|
||||
*/
|
||||
constructor(do_debug = false) {
|
||||
this.taLog = new taLogger("mzta-storage", do_debug);
|
||||
}
|
||||
|
|
@ -179,10 +182,11 @@ export class taStorage {
|
|||
/**
|
||||
* Write the summary field for a given Message-ID.
|
||||
* @param {string} messageId - The Message-ID header string.
|
||||
* @param {string} text - The summary text.
|
||||
* @param {object} summary_data - The summary data object with fields:
|
||||
* summary, error, message, summary_date.
|
||||
* @param {boolean} [force=true] - If true, overwrite existing summary data.
|
||||
*/
|
||||
async writeSummary(messageId, text, force = true) {
|
||||
async writeSummary(messageId, summary_data, force = true) {
|
||||
this.taLog.log('[writeSummary] messageId: ' + messageId + ', force: ' + force);
|
||||
try {
|
||||
let key = this._buildKey(messageId);
|
||||
|
|
@ -192,7 +196,15 @@ export class taStorage {
|
|||
return;
|
||||
}
|
||||
let now = Date.now();
|
||||
record[taStorage.FIELD_SUMMARY] = { text: text, ts: now };
|
||||
record[taStorage.FIELD_SUMMARY] = {
|
||||
summary: summary_data.summary,
|
||||
error: summary_data.error || false,
|
||||
message: summary_data.message || '',
|
||||
summary_date: summary_data.summary_date instanceof Date
|
||||
? summary_data.summary_date.toISOString()
|
||||
: summary_data.summary_date,
|
||||
ts: now,
|
||||
};
|
||||
record.ts = now;
|
||||
await messenger.storage.local.set({ [key]: record });
|
||||
} catch (e) {
|
||||
|
|
@ -200,6 +212,64 @@ export class taStorage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all records that contain a summary field.
|
||||
* @returns {Promise<object>} Map of messageId -> summary data object.
|
||||
*/
|
||||
async getAllSummaryRecords() {
|
||||
this.taLog.log('[getAllSummaryRecords] loading all summary records');
|
||||
try {
|
||||
let all = await messenger.storage.local.get(null);
|
||||
let result = {};
|
||||
for (let [key, record] of Object.entries(all)) {
|
||||
if (!key.startsWith(taStorage.STORAGE_KEY_PREFIX)) continue;
|
||||
if (!this.hasField(record, taStorage.FIELD_SUMMARY)) continue;
|
||||
let messageId = key.slice(taStorage.STORAGE_KEY_PREFIX.length);
|
||||
let summary = record[taStorage.FIELD_SUMMARY];
|
||||
result[messageId] = {
|
||||
headerMessageId: messageId,
|
||||
summary: summary.summary,
|
||||
error: summary.error || false,
|
||||
message: summary.message || '',
|
||||
summary_date: new Date(summary.summary_date || summary.ts),
|
||||
};
|
||||
}
|
||||
this.taLog.log('[getAllSummaryRecords] found ' + Object.keys(result).length + ' summary records');
|
||||
return result;
|
||||
} catch (e) {
|
||||
this.taLog.error('getAllSummaryRecords error: ' + e);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete only the summary field from a record.
|
||||
* Deletes the entire record if no other data fields remain.
|
||||
* @param {string} messageId - The Message-ID header string.
|
||||
*/
|
||||
async deleteSummaryField(messageId) {
|
||||
this.taLog.log('[deleteSummaryField] messageId: ' + messageId);
|
||||
try {
|
||||
let key = this._buildKey(messageId);
|
||||
let record = await this.getRecord(messageId);
|
||||
if (!record || !(taStorage.FIELD_SUMMARY in record)) {
|
||||
this.taLog.log('[deleteSummaryField] no summary field found for messageId: ' + messageId);
|
||||
return;
|
||||
}
|
||||
delete record[taStorage.FIELD_SUMMARY];
|
||||
const remainingFields = Object.keys(record).filter(k => k !== 'v' && k !== 'ts');
|
||||
if (remainingFields.length === 0) {
|
||||
this.taLog.log('[deleteSummaryField] no remaining fields, deleting entire record');
|
||||
await messenger.storage.local.remove(key);
|
||||
} else {
|
||||
this.taLog.log('[deleteSummaryField] remaining fields: ' + remainingFields.join(', '));
|
||||
await messenger.storage.local.set({ [key]: record });
|
||||
}
|
||||
} catch (e) {
|
||||
this.taLog.error('deleteSummaryField error: ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the translation field for a given Message-ID.
|
||||
* @param {string} messageId - The Message-ID header string.
|
||||
|
|
|
|||
|
|
@ -16,30 +16,49 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const taSummaryStore = {
|
||||
logger: console,
|
||||
_data_prefix: 'mzta-summary-',
|
||||
_processing_prefix: 'mzta-summary-processing-',
|
||||
_max_summaries: 100,
|
||||
import { taStorage } from './mzta-storage.js';
|
||||
import { taLogger } from './mzta-logger.js';
|
||||
|
||||
export class taSummaryStore {
|
||||
|
||||
_processing_prefix = 'mzta-summary-processing-';
|
||||
_max_summaries = 100;
|
||||
_storage = null;
|
||||
taLog = null;
|
||||
|
||||
constructor(do_debug = false) {
|
||||
this._storage = new taStorage(do_debug);
|
||||
this.taLog = new taLogger('mzta-summarystore', do_debug);
|
||||
}
|
||||
|
||||
async setProcessing(data_id) {
|
||||
this.taLog.log("[setProcessing] data_id: " + data_id);
|
||||
const key = this._processing_prefix + data_id;
|
||||
await browser.storage.session.set({ [key]: true });
|
||||
},
|
||||
}
|
||||
|
||||
async isProcessing(data_id) {
|
||||
this.taLog.log("[isProcessing] data_id: " + data_id);
|
||||
const key = this._processing_prefix + data_id;
|
||||
let output = await browser.storage.session.get(key);
|
||||
return output[key] || false;
|
||||
},
|
||||
let result = output[key] || false;
|
||||
this.taLog.log("[isProcessing] result: " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
async saveSummary(data, data_id) {
|
||||
const key = this._data_prefix + data_id;
|
||||
await browser.storage.session.set({ [key]: data });
|
||||
await browser.storage.session.remove(this._processing_prefix + data_id);
|
||||
},
|
||||
this.taLog.log("[saveSummary] data_id: " + data_id);
|
||||
try {
|
||||
await this._storage.writeSummary(data_id, data, true);
|
||||
await browser.storage.session.remove(this._processing_prefix + data_id);
|
||||
} catch (e) {
|
||||
this.taLog.error("[saveSummary] error: " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async saveError(data_id, error_message) {
|
||||
this.taLog.log("[saveError] data_id: " + data_id + ", error_message: " + error_message);
|
||||
let data = {
|
||||
error: true,
|
||||
message: error_message,
|
||||
|
|
@ -48,53 +67,67 @@ export const taSummaryStore = {
|
|||
};
|
||||
await this.saveSummary(data, data_id);
|
||||
return data;
|
||||
},
|
||||
}
|
||||
|
||||
async loadSummary(data_id) {
|
||||
const key = this._data_prefix + data_id;
|
||||
let output = await browser.storage.session.get(key);
|
||||
return output[key] || null;
|
||||
},
|
||||
this.taLog.log("[loadSummary] data_id: " + data_id);
|
||||
let record = await this._storage.getRecord(data_id);
|
||||
if (!record || !this._storage.hasField(record, taStorage.FIELD_SUMMARY)) {
|
||||
this.taLog.log("[loadSummary] no record found for data_id: " + data_id);
|
||||
return null;
|
||||
}
|
||||
let summary = record.summary;
|
||||
return {
|
||||
headerMessageId: data_id,
|
||||
summary: summary.summary,
|
||||
error: summary.error || false,
|
||||
message: summary.message || '',
|
||||
summary_date: new Date(summary.summary_date || summary.ts),
|
||||
};
|
||||
}
|
||||
|
||||
async removeSummary(data_id) {
|
||||
const key = this._data_prefix + data_id;
|
||||
await browser.storage.session.remove(key);
|
||||
this.taLog.log("[removeSummary] data_id: " + data_id);
|
||||
await this._storage.deleteSummaryField(data_id);
|
||||
await browser.storage.session.remove(this._processing_prefix + data_id);
|
||||
},
|
||||
}
|
||||
|
||||
async getAllSummaries() {
|
||||
let allData = await browser.storage.session.get(null);
|
||||
let summaryData = {};
|
||||
|
||||
for (const [key, value] of Object.entries(allData)) {
|
||||
if (key.startsWith(this._data_prefix)) {
|
||||
summaryData[key.replace(this._data_prefix, '')] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return summaryData;
|
||||
},
|
||||
this.taLog.log("[getAllSummaries] loading all summaries");
|
||||
return await this._storage.getAllSummaryRecords();
|
||||
}
|
||||
|
||||
async clearSummaries() {
|
||||
let allData = await browser.storage.session.get(null);
|
||||
let keysToDelete = Object.keys(allData).filter(key => key.startsWith(this._data_prefix) || key.startsWith(this._processing_prefix));
|
||||
|
||||
this.taLog.log("[clearSummaries] clearing all summary data");
|
||||
let allSummaries = await this._storage.getAllSummaryRecords();
|
||||
let summaryKeys = Object.keys(allSummaries);
|
||||
this.taLog.log("[clearSummaries] deleting " + summaryKeys.length + " summary records");
|
||||
for (let messageId of summaryKeys) {
|
||||
await this._storage.deleteSummaryField(messageId);
|
||||
}
|
||||
let allSession = await browser.storage.session.get(null);
|
||||
let keysToDelete = Object.keys(allSession).filter(k => k.startsWith(this._processing_prefix));
|
||||
this.taLog.log("[clearSummaries] deleting " + keysToDelete.length + " session keys");
|
||||
for (let key of keysToDelete) {
|
||||
await browser.storage.session.remove(key);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
async truncSummaries() {
|
||||
let data = await this.getAllSummaries();
|
||||
this.taLog.log("[truncSummaries] checking summary count");
|
||||
let data = await this._storage.getAllSummaryRecords();
|
||||
let sortedData = this.sortSummariesByDate(data);
|
||||
let keys = Object.keys(sortedData);
|
||||
this.taLog.log("[truncSummaries] total summaries: " + keys.length + ", max: " + this._max_summaries);
|
||||
|
||||
if (keys.length > this._max_summaries) {
|
||||
let toDelete = keys.length - this._max_summaries;
|
||||
this.taLog.log("[truncSummaries] truncating " + toDelete + " oldest summaries");
|
||||
for (let i = this._max_summaries; i < keys.length; i++) {
|
||||
await browser.storage.session.remove(this._data_prefix + keys[i]);
|
||||
await this._storage.deleteSummaryField(keys[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
sortSummariesByDate(data) {
|
||||
if (!data) return {};
|
||||
|
|
@ -112,4 +145,4 @@ export const taSummaryStore = {
|
|||
|
||||
return sortedSummaries;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ await reload_pref_init();
|
|||
let taLog = new taLogger("mzta-background",prefs_init.do_debug);
|
||||
taWorkingStatus.taLog = taLog;
|
||||
let spamReport = new taSpamReport(prefs_init.do_debug);
|
||||
let summaryStore = new taSummaryStore(prefs_init.do_debug);
|
||||
|
||||
let special_prompts_ids = getActiveSpecialPromptsIDs({
|
||||
addtags: prefs_init.add_tags,
|
||||
|
|
@ -227,13 +228,13 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||
let message = await browser.messageDisplay.getDisplayedMessage(tabId);
|
||||
if (!message) return;
|
||||
|
||||
let cachedSummary = await taSummaryStore.loadSummary(message.headerMessageId);
|
||||
let cachedSummary = await summaryStore.loadSummary(message.headerMessageId);
|
||||
if (cachedSummary && !cachedSummary.error) {
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary });
|
||||
return;
|
||||
}
|
||||
|
||||
if (await taSummaryStore.isProcessing(message.headerMessageId)) {
|
||||
if (await summaryStore.isProcessing(message.headerMessageId)) {
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummaryGenerating" });
|
||||
return;
|
||||
}
|
||||
|
|
@ -265,7 +266,7 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||
case 'refreshSummary':
|
||||
async function _refreshSummary(message) {
|
||||
let tabId = sender.tab.id;
|
||||
await taSummaryStore.removeSummary(message.headerMessageId);
|
||||
await summaryStore.removeSummary(message.headerMessageId);
|
||||
await _generateSummaryForMessage(message.headerMessageId, tabId);
|
||||
}
|
||||
_refreshSummary(message);
|
||||
|
|
@ -445,23 +446,23 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
|||
...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])
|
||||
});
|
||||
|
||||
let cachedSummary = await taSummaryStore.loadSummary(headerMessageId);
|
||||
let cachedSummary = await summaryStore.loadSummary(headerMessageId);
|
||||
if (cachedSummary && !cachedSummary.error) {
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary });
|
||||
return;
|
||||
}
|
||||
|
||||
if (await taSummaryStore.isProcessing(headerMessageId)) {
|
||||
if (await summaryStore.isProcessing(headerMessageId)) {
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummaryGenerating" });
|
||||
return;
|
||||
}
|
||||
|
||||
await taSummaryStore.setProcessing(headerMessageId);
|
||||
await summaryStore.setProcessing(headerMessageId);
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummaryGenerating" });
|
||||
|
||||
const messageResult = await browser.messages.query({ headerMessageId: headerMessageId });
|
||||
if (!messageResult || messageResult.messages.length === 0) {
|
||||
await taSummaryStore.saveError(headerMessageId, "Message not found");
|
||||
await summaryStore.saveError(headerMessageId, "Message not found");
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: { error: true, message: "Message not found" } });
|
||||
return;
|
||||
}
|
||||
|
|
@ -479,7 +480,7 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
|||
|
||||
if (connectionType === 'chatgpt_web') {
|
||||
const errorMsg = browser.i18n.getMessage('summarize_chatgpt_web_not_supported');
|
||||
await taSummaryStore.saveError(headerMessageId, errorMsg);
|
||||
await summaryStore.saveError(headerMessageId, errorMsg);
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: { error: true, message: errorMsg } });
|
||||
return;
|
||||
}
|
||||
|
|
@ -503,12 +504,12 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
|||
summary_date: new Date(),
|
||||
headerMessageId: headerMessageId
|
||||
};
|
||||
await taSummaryStore.saveSummary(summaryData, headerMessageId);
|
||||
await summaryStore.saveSummary(summaryData, headerMessageId);
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: summaryData });
|
||||
|
||||
} catch (error) {
|
||||
console.error("[ThunderAI] Error generating summary:", error);
|
||||
await taSummaryStore.saveError(headerMessageId, error.message || String(error));
|
||||
await summaryStore.saveError(headerMessageId, error.message || String(error));
|
||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: { error: true, message: error.message || "Failed to generate summary" } });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue