308 lines
9.8 KiB
TypeScript
308 lines
9.8 KiB
TypeScript
/**
|
|
* Enhanced persistence utility for CopilotKit integration
|
|
* Uses localStorage and CopilotKit hooks for better state management
|
|
*/
|
|
|
|
import { useCopilotContext } from '@copilotkit/react-core';
|
|
|
|
// Storage keys for different types of data
|
|
export const STORAGE_KEYS = {
|
|
CHAT_HISTORY: 'alwrity-copilot-chat-history',
|
|
USER_PREFERENCES: 'alwrity-copilot-user-preferences',
|
|
CONVERSATION_CONTEXT: 'alwrity-copilot-conversation-context',
|
|
DRAFT_CONTENT: 'alwrity-copilot-draft-content',
|
|
LAST_SESSION: 'alwrity-copilot-last-session'
|
|
};
|
|
|
|
// Chat message interface
|
|
export interface ChatMessage {
|
|
id: string;
|
|
role: 'user' | 'assistant';
|
|
content: string;
|
|
timestamp: number;
|
|
metadata?: {
|
|
action?: string;
|
|
result?: any;
|
|
context?: string;
|
|
};
|
|
}
|
|
|
|
// User preferences interface
|
|
export interface UserPreferences {
|
|
tone: string;
|
|
industry: string;
|
|
target_audience: string;
|
|
content_goals: string[];
|
|
writing_style: string;
|
|
hashtag_preferences: boolean;
|
|
cta_preferences: boolean;
|
|
last_used_actions: string[];
|
|
favorite_topics: string[];
|
|
last_updated: number;
|
|
}
|
|
|
|
// Conversation context interface
|
|
export interface ConversationContext {
|
|
currentTopic: string;
|
|
industry: string;
|
|
tone: string;
|
|
targetAudience: string;
|
|
keyPoints: string[];
|
|
lastUpdated: number;
|
|
}
|
|
|
|
// Main persistence manager class
|
|
export class CopilotPersistenceManager {
|
|
private static instance: CopilotPersistenceManager;
|
|
|
|
private constructor() {}
|
|
|
|
public static getInstance(): CopilotPersistenceManager {
|
|
if (!CopilotPersistenceManager.instance) {
|
|
CopilotPersistenceManager.instance = new CopilotPersistenceManager();
|
|
}
|
|
return CopilotPersistenceManager.instance;
|
|
}
|
|
|
|
// Chat history persistence
|
|
public saveChatHistory(messages: ChatMessage[]): void {
|
|
try {
|
|
// Keep only last 100 messages to prevent excessive storage
|
|
const trimmedMessages = messages.slice(-100);
|
|
localStorage.setItem(STORAGE_KEYS.CHAT_HISTORY, JSON.stringify(trimmedMessages));
|
|
console.log(`💾 Saved ${trimmedMessages.length} chat messages`);
|
|
} catch (error) {
|
|
console.error('❌ Failed to save chat history:', error);
|
|
}
|
|
}
|
|
|
|
public loadChatHistory(): ChatMessage[] {
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEYS.CHAT_HISTORY);
|
|
if (!stored) return [];
|
|
|
|
const messages = JSON.parse(stored);
|
|
console.log(`📖 Loaded ${messages.length} chat messages`);
|
|
return messages;
|
|
} catch (error) {
|
|
console.error('❌ Failed to load chat history:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public addChatMessage(message: ChatMessage): void {
|
|
try {
|
|
const existing = this.loadChatHistory();
|
|
existing.push(message);
|
|
this.saveChatHistory(existing);
|
|
} catch (error) {
|
|
console.error('❌ Failed to add chat message:', error);
|
|
}
|
|
}
|
|
|
|
// User preferences persistence
|
|
public saveUserPreferences(preferences: Partial<UserPreferences>): void {
|
|
try {
|
|
const existing = this.loadUserPreferences();
|
|
const updated = { ...existing, ...preferences, last_updated: Date.now() };
|
|
localStorage.setItem(STORAGE_KEYS.USER_PREFERENCES, JSON.stringify(updated));
|
|
console.log('💾 Saved user preferences');
|
|
} catch (error) {
|
|
console.error('❌ Failed to save user preferences:', error);
|
|
}
|
|
}
|
|
|
|
public loadUserPreferences(): UserPreferences {
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEYS.USER_PREFERENCES);
|
|
if (!stored) {
|
|
return {
|
|
tone: 'Professional',
|
|
industry: 'Technology',
|
|
target_audience: 'Professionals',
|
|
content_goals: ['Engagement', 'Thought Leadership'],
|
|
writing_style: 'Clear and Concise',
|
|
hashtag_preferences: true,
|
|
cta_preferences: true,
|
|
last_used_actions: [],
|
|
favorite_topics: [],
|
|
last_updated: Date.now()
|
|
};
|
|
}
|
|
|
|
const preferences = JSON.parse(stored);
|
|
console.log('📖 Loaded user preferences');
|
|
return preferences;
|
|
} catch (error) {
|
|
console.error('❌ Failed to load user preferences:', error);
|
|
// Return default preferences instead of recursive call
|
|
return {
|
|
tone: 'Professional',
|
|
industry: 'Technology',
|
|
target_audience: 'Professionals',
|
|
content_goals: ['Engagement', 'Thought Leadership'],
|
|
writing_style: 'Clear and Concise',
|
|
hashtag_preferences: true,
|
|
cta_preferences: true,
|
|
last_used_actions: [],
|
|
favorite_topics: [],
|
|
last_updated: Date.now()
|
|
};
|
|
}
|
|
}
|
|
|
|
// Conversation context persistence
|
|
public saveConversationContext(context: Partial<ConversationContext>): void {
|
|
try {
|
|
const existing = this.loadConversationContext();
|
|
const updated = { ...existing, ...context, lastUpdated: Date.now() };
|
|
localStorage.setItem(STORAGE_KEYS.CONVERSATION_CONTEXT, JSON.stringify(updated));
|
|
console.log('💾 Saved conversation context');
|
|
} catch (error) {
|
|
console.error('❌ Failed to save conversation context:', error);
|
|
}
|
|
}
|
|
|
|
public loadConversationContext(): ConversationContext {
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEYS.CONVERSATION_CONTEXT);
|
|
if (!stored) {
|
|
return {
|
|
currentTopic: '',
|
|
industry: 'Technology',
|
|
tone: 'Professional',
|
|
targetAudience: 'Professionals',
|
|
keyPoints: [],
|
|
lastUpdated: Date.now()
|
|
};
|
|
}
|
|
|
|
const context = JSON.parse(stored);
|
|
console.log('📖 Loaded conversation context');
|
|
return context;
|
|
} catch (error) {
|
|
console.error('❌ Failed to load conversation context:', error);
|
|
// Return default context instead of recursive call
|
|
return {
|
|
currentTopic: '',
|
|
industry: 'Technology',
|
|
tone: 'Professional',
|
|
targetAudience: 'Professionals',
|
|
keyPoints: [],
|
|
lastUpdated: Date.now()
|
|
};
|
|
}
|
|
}
|
|
|
|
// Draft content persistence
|
|
public saveDraftContent(draft: string): void {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEYS.DRAFT_CONTENT, draft);
|
|
console.log('💾 Saved draft content');
|
|
} catch (error) {
|
|
console.error('❌ Failed to save draft content:', error);
|
|
}
|
|
}
|
|
|
|
public loadDraftContent(): string {
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEYS.DRAFT_CONTENT);
|
|
if (stored) {
|
|
console.log('📖 Loaded draft content');
|
|
return stored;
|
|
}
|
|
return '';
|
|
} catch (error) {
|
|
console.error('❌ Failed to load draft content:', error);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
// Session management
|
|
public saveLastSession(): void {
|
|
try {
|
|
const sessionData = {
|
|
timestamp: Date.now(),
|
|
url: window.location.href,
|
|
userAgent: navigator.userAgent
|
|
};
|
|
localStorage.setItem(STORAGE_KEYS.LAST_SESSION, JSON.stringify(sessionData));
|
|
console.log('💾 Saved session data');
|
|
} catch (error) {
|
|
console.error('❌ Failed to save session data:', error);
|
|
}
|
|
}
|
|
|
|
public loadLastSession(): any {
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEYS.LAST_SESSION);
|
|
if (stored) {
|
|
const session = JSON.parse(stored);
|
|
console.log('📖 Loaded session data');
|
|
return session;
|
|
}
|
|
return null;
|
|
} catch (error) {
|
|
console.error('❌ Failed to load session data:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Clear all persistence data
|
|
public clearAllData(): void {
|
|
try {
|
|
Object.values(STORAGE_KEYS).forEach(key => {
|
|
localStorage.removeItem(key);
|
|
});
|
|
console.log('🗑️ Cleared all persistence data');
|
|
} catch (error) {
|
|
console.error('❌ Failed to clear persistence data:', error);
|
|
}
|
|
}
|
|
|
|
// Get storage statistics
|
|
public getStorageStats(): any {
|
|
try {
|
|
const stats = {
|
|
chatHistory: this.loadChatHistory().length,
|
|
hasUserPreferences: !!localStorage.getItem(STORAGE_KEYS.USER_PREFERENCES),
|
|
hasConversationContext: !!localStorage.getItem(STORAGE_KEYS.CONVERSATION_CONTEXT),
|
|
hasDraftContent: !!localStorage.getItem(STORAGE_KEYS.DRAFT_CONTENT),
|
|
hasLastSession: !!localStorage.getItem(STORAGE_KEYS.LAST_SESSION),
|
|
totalKeys: Object.keys(localStorage).filter(key => key.includes('alwrity-copilot')).length
|
|
};
|
|
|
|
console.log('📊 Storage statistics:', stats);
|
|
return stats;
|
|
} catch (error) {
|
|
console.error('❌ Failed to get storage stats:', error);
|
|
return {};
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hook for using persistence in React components
|
|
export const useCopilotPersistence = () => {
|
|
const copilotContext = useCopilotContext();
|
|
const persistenceManager = CopilotPersistenceManager.getInstance();
|
|
|
|
return {
|
|
persistenceManager,
|
|
copilotContext,
|
|
// Convenience methods
|
|
saveChatHistory: persistenceManager.saveChatHistory.bind(persistenceManager),
|
|
loadChatHistory: persistenceManager.loadChatHistory.bind(persistenceManager),
|
|
addChatMessage: persistenceManager.addChatMessage.bind(persistenceManager),
|
|
saveUserPreferences: persistenceManager.saveUserPreferences.bind(persistenceManager),
|
|
loadUserPreferences: persistenceManager.loadUserPreferences.bind(persistenceManager),
|
|
saveConversationContext: persistenceManager.saveConversationContext.bind(persistenceManager),
|
|
loadConversationContext: persistenceManager.loadConversationContext.bind(persistenceManager),
|
|
saveDraftContent: persistenceManager.saveDraftContent.bind(persistenceManager),
|
|
loadDraftContent: persistenceManager.loadDraftContent.bind(persistenceManager),
|
|
saveLastSession: persistenceManager.saveLastSession.bind(persistenceManager),
|
|
loadLastSession: persistenceManager.loadLastSession.bind(persistenceManager),
|
|
clearAllData: persistenceManager.clearAllData.bind(persistenceManager),
|
|
getStorageStats: persistenceManager.getStorageStats.bind(persistenceManager)
|
|
};
|
|
};
|