v3.1.0: Add parser error detection and recommended models section

This commit is contained in:
Spicy_Marinara
2026-01-07 22:56:26 +01:00
parent dbf5c2d17a
commit a3063aff4f
33 changed files with 599 additions and 459 deletions
+11 -6
View File
@@ -62,7 +62,7 @@ export async function generateWithExternalAPI(messages) {
const normalizedBaseUrl = baseUrl.trim().replace(/\/+$/, '');
const endpoint = `${normalizedBaseUrl}/chat/completions`;
console.log(`[RPG Companion] Calling external API: ${normalizedBaseUrl} with model: ${model}`);
// console.log(`[RPG Companion] Calling external API: ${normalizedBaseUrl} with model: ${model}`);
try {
const response = await fetch(endpoint, {
@@ -103,7 +103,7 @@ export async function generateWithExternalAPI(messages) {
}
const content = data.choices[0].message.content;
console.log('[RPG Companion] External API response received successfully');
// console.log('[RPG Companion] External API response received successfully');
return content;
} catch (error) {
@@ -242,7 +242,7 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough
let response;
if (isExternalMode) {
// External mode: Use external OpenAI-compatible API directly
console.log('[RPG Companion] Using external API for tracker generation');
// console.log('[RPG Companion] Using external API for tracker generation');
response = await generateWithExternalAPI(prompt);
} else {
// Separate mode: Use SillyTavern's generateRaw
@@ -256,6 +256,11 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough
// console.log('[RPG Companion] Raw AI response:', response);
const parsedData = parseResponse(response);
// Check if parsing completely failed (no tracker data found)
if (parsedData.parsingFailed) {
toastr.error(i18n.getTranslation('errors.parsingError'), '', { timeOut: 5000 });
}
// Remove locks from parsed data (JSON format only, text format is unaffected)
if (parsedData.userStats) {
parsedData.userStats = removeLocks(parsedData.userStats);
@@ -358,17 +363,17 @@ export async function updateRPGData(renderUserStats, renderInfoBox, renderThough
if (extensionSettings.autoGenerateAvatars) {
const charactersNeedingAvatars = parseCharactersFromThoughts(parsedData.characterThoughts);
if (charactersNeedingAvatars.length > 0) {
console.log('[RPG Companion] Generating avatars for:', charactersNeedingAvatars);
// console.log('[RPG Companion] Generating avatars for:', charactersNeedingAvatars);
// Generate avatars - this awaits completion
await generateAvatarsForCharacters(charactersNeedingAvatars, (names) => {
// Callback when generation starts - re-render to show loading spinners
console.log('[RPG Companion] Avatar generation started, showing spinners...');
// console.log('[RPG Companion] Avatar generation started, showing spinners...');
renderThoughts();
});
// Re-render once all avatars are generated
console.log('[RPG Companion] All avatars generated, re-rendering...');
// console.log('[RPG Companion] All avatars generated, re-rendering...');
renderThoughts();
}
}
+14 -14
View File
@@ -97,14 +97,14 @@ export async function buildEncounterInitPrompt() {
try {
// Debug logging
console.log('[RPG Companion] Checking world info:', {
hasWindowGetWorldInfoPrompt: typeof window.getWorldInfoPrompt === 'function',
hasContextGetWorldInfoPrompt: typeof context.getWorldInfoPrompt === 'function',
chatLength: chat?.length,
contextChatLength: context.chat?.length,
hasActivatedWorldInfo: !!context.activatedWorldInfo,
activatedWorldInfoLength: context.activatedWorldInfo?.length
});
// console.log('[RPG Companion] Checking world info:', {
// hasWindowGetWorldInfoPrompt: typeof window.getWorldInfoPrompt === 'function',
// hasContextGetWorldInfoPrompt: typeof context.getWorldInfoPrompt === 'function',
// chatLength: chat?.length,
// contextChatLength: context.chat?.length,
// hasActivatedWorldInfo: !!context.activatedWorldInfo,
// activatedWorldInfoLength: context.activatedWorldInfo?.length
// });
// Use SillyTavern's getWorldInfoPrompt to get activated lorebook entries
// Try context.getWorldInfoPrompt first, then window.getWorldInfoPrompt
@@ -114,20 +114,20 @@ export async function buildEncounterInitPrompt() {
if (typeof getWorldInfoFn === 'function' && currentChat && currentChat.length > 0) {
const chatForWI = currentChat.map(x => x.mes || x.message || x).filter(m => m && typeof m === 'string');
console.log('[RPG Companion] Calling getWorldInfoPrompt with', chatForWI.length, 'messages');
// console.log('[RPG Companion] Calling getWorldInfoPrompt with', chatForWI.length, 'messages');
const result = await getWorldInfoFn(chatForWI, 8000, false);
const worldInfoString = result?.worldInfoString || result;
console.log('[RPG Companion] World info result:', { worldInfoString, length: worldInfoString?.length });
// console.log('[RPG Companion] World info result:', { worldInfoString, length: worldInfoString?.length });
if (worldInfoString && worldInfoString.trim()) {
systemMessage += worldInfoString.trim();
worldInfoAdded = true;
console.log('[RPG Companion] ✅ Added world info from getWorldInfoPrompt');
// console.log('[RPG Companion] ✅ Added world info from getWorldInfoPrompt');
}
} else {
console.log('[RPG Companion] getWorldInfoPrompt not available or no chat');
// console.log('[RPG Companion] getWorldInfoPrompt not available or no chat');
}
} catch (e) {
console.warn('[RPG Companion] Failed to get world info from getWorldInfoPrompt:', e);
@@ -135,7 +135,7 @@ export async function buildEncounterInitPrompt() {
// Fallback to activatedWorldInfo
if (!worldInfoAdded && context.activatedWorldInfo && Array.isArray(context.activatedWorldInfo) && context.activatedWorldInfo.length > 0) {
console.log('[RPG Companion] Using fallback activatedWorldInfo:', context.activatedWorldInfo.length, 'entries');
// console.log('[RPG Companion] Using fallback activatedWorldInfo:', context.activatedWorldInfo.length, 'entries');
context.activatedWorldInfo.forEach((entry) => {
if (entry && entry.content) {
systemMessage += `${entry.content}\n\n`;
@@ -745,7 +745,7 @@ export function parseEncounterJSON(response) {
const repaired = repairJSON(cleaned);
if (repaired) {
console.log('[RPG Companion] ✓ Successfully repaired encounter JSON');
// console.log('[RPG Companion] ✓ Successfully repaired encounter JSON');
return repaired;
}
+53 -53
View File
@@ -44,15 +44,15 @@ let lastCommittedChatLength = -1;
export async function onGenerationStarted(type, data, dryRun) {
// Skip dry runs (page reload, prompt manager preview, etc.)
if (dryRun) {
console.log('[RPG Companion] Skipping onGenerationStarted: dry run detected');
// console.log('[RPG Companion] Skipping onGenerationStarted: dry run detected');
return;
}
console.log('[RPG Companion] onGenerationStarted called');
console.log('[RPG Companion] enabled:', extensionSettings.enabled);
console.log('[RPG Companion] generationMode:', extensionSettings.generationMode);
console.log('[RPG Companion] ⚡ EVENT: onGenerationStarted - lastActionWasSwipe =', lastActionWasSwipe, '| isGenerating =', isGenerating);
console.log('[RPG Companion] Committed Prompt:', committedTrackerData);
// console.log('[RPG Companion] onGenerationStarted called');
// console.log('[RPG Companion] enabled:', extensionSettings.enabled);
// console.log('[RPG Companion] generationMode:', extensionSettings.generationMode);
// console.log('[RPG Companion] ⚡ EVENT: onGenerationStarted - lastActionWasSwipe =', lastActionWasSwipe, '| isGenerating =', isGenerating);
// console.log('[RPG Companion] Committed Prompt:', committedTrackerData);
// Skip tracker injection for image generation requests
if (data?.quietImage) {
@@ -115,18 +115,18 @@ export async function onGenerationStarted(type, data, dryRun) {
const shouldCommit = isUserMessage && !lastActionWasSwipe && currentChatLength !== lastCommittedChatLength;
if (shouldCommit) {
console.log('[RPG Companion] 📝 TOGETHER MODE COMMIT: User sent message - committing data from BEFORE user message');
console.log('[RPG Companion] Chat length:', currentChatLength, 'Last committed:', lastCommittedChatLength);
console.log('[RPG Companion] BEFORE: committedTrackerData =', {
userStats: committedTrackerData.userStats ? `${committedTrackerData.userStats.substring(0, 50)}...` : 'null',
infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
characterThoughts: committedTrackerData.characterThoughts ? `${committedTrackerData.characterThoughts.substring(0, 100)}...` : 'null'
});
console.log('[RPG Companion] BEFORE: lastGeneratedData =', {
userStats: lastGeneratedData.userStats ? `${lastGeneratedData.userStats.substring(0, 50)}...` : 'null',
infoBox: lastGeneratedData.infoBox ? 'exists' : 'null',
characterThoughts: lastGeneratedData.characterThoughts ? `${lastGeneratedData.characterThoughts.substring(0, 100)}...` : 'null'
});
// console.log('[RPG Companion] 📝 TOGETHER MODE COMMIT: User sent message - committing data from BEFORE user message');
// console.log('[RPG Companion] Chat length:', currentChatLength, 'Last committed:', lastCommittedChatLength);
// console.log('[RPG Companion] BEFORE: committedTrackerData =', {
// userStats: committedTrackerData.userStats ? `${committedTrackerData.userStats.substring(0, 50)}...` : 'null',
// infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
// characterThoughts: committedTrackerData.characterThoughts ? `${committedTrackerData.characterThoughts.substring(0, 100)}...` : 'null'
// // });
// console.log('[RPG Companion] BEFORE: lastGeneratedData =', {
// userStats: lastGeneratedData.userStats ? `${lastGeneratedData.userStats.substring(0, 50)}...` : 'null',
// infoBox: lastGeneratedData.infoBox ? 'exists' : 'null',
// characterThoughts: lastGeneratedData.characterThoughts ? `${lastGeneratedData.characterThoughts.substring(0, 100)}...` : 'null'
// });
// Commit displayed data (from before user sent message)
committedTrackerData.userStats = lastGeneratedData.userStats;
@@ -136,23 +136,23 @@ export async function onGenerationStarted(type, data, dryRun) {
// Track chat length to prevent duplicate commits
lastCommittedChatLength = currentChatLength;
console.log('[RPG Companion] AFTER: committedTrackerData =', {
userStats: committedTrackerData.userStats ? `${committedTrackerData.userStats.substring(0, 50)}...` : 'null',
infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
characterThoughts: committedTrackerData.characterThoughts ? `${committedTrackerData.characterThoughts.substring(0, 100)}...` : 'null'
});
// console.log('[RPG Companion] AFTER: committedTrackerData =', {
// userStats: committedTrackerData.userStats ? `${committedTrackerData.userStats.substring(0, 50)}...` : 'null',
// infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
// characterThoughts: committedTrackerData.characterThoughts ? `${committedTrackerData.characterThoughts.substring(0, 100)}...` : 'null'
// });
} else if (lastActionWasSwipe) {
console.log('[RPG Companion] ⏭️ Skipping commit: swipe (using previous committed data)');
// console.log('[RPG Companion] ⏭️ Skipping commit: swipe (using previous committed data)');
} else if (!isUserMessage) {
console.log('[RPG Companion] ⏭️ Skipping commit: second-to-last message is not user message (likely swipe or continuation)');
// console.log('[RPG Companion] ⏭️ Skipping commit: second-to-last message is not user message (likely swipe or continuation)');
}
console.log('[RPG Companion] 📦 TOGETHER MODE: Injecting committed tracker data into prompt');
console.log('[RPG Companion] committedTrackerData =', {
userStats: committedTrackerData.userStats ? `${committedTrackerData.userStats.substring(0, 50)}...` : 'null',
infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
characterThoughts: committedTrackerData.characterThoughts ? `${committedTrackerData.characterThoughts.substring(0, 100)}...` : 'null'
});
// console.log('[RPG Companion] 📦 TOGETHER MODE: Injecting committed tracker data into prompt');
// console.log('[RPG Companion] committedTrackerData =', {
// userStats: committedTrackerData.userStats ? `${committedTrackerData.userStats.substring(0, 50)}...` : 'null',
// infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
// characterThoughts: committedTrackerData.characterThoughts ? `${committedTrackerData.characterThoughts.substring(0, 100)}...` : 'null'
// });
}
// For SEPARATE mode only: Check if we need to commit extension data
@@ -162,35 +162,35 @@ export async function onGenerationStarted(type, data, dryRun) {
if (extensionSettings.generationMode === 'separate' && !isGenerating) {
if (!lastActionWasSwipe) {
// User sent a new message - commit lastGeneratedData before generation
console.log('[RPG Companion] 📝 COMMIT: New message - committing lastGeneratedData');
console.log('[RPG Companion] BEFORE commit - committedTrackerData:', {
userStats: committedTrackerData.userStats ? 'exists' : 'null',
infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
characterThoughts: committedTrackerData.characterThoughts ? 'exists' : 'null'
});
console.log('[RPG Companion] BEFORE commit - lastGeneratedData:', {
userStats: lastGeneratedData.userStats ? 'exists' : 'null',
infoBox: lastGeneratedData.infoBox ? 'exists' : 'null',
characterThoughts: lastGeneratedData.characterThoughts ? 'exists' : 'null'
});
// console.log('[RPG Companion] 📝 COMMIT: New message - committing lastGeneratedData');
// console.log('[RPG Companion] BEFORE commit - committedTrackerData:', {
// userStats: committedTrackerData.userStats ? 'exists' : 'null',
// infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
// characterThoughts: committedTrackerData.characterThoughts ? 'exists' : 'null'
// // });
// console.log('[RPG Companion] BEFORE commit - lastGeneratedData:', {
// userStats: lastGeneratedData.userStats ? 'exists' : 'null',
// infoBox: lastGeneratedData.infoBox ? 'exists' : 'null',
// characterThoughts: lastGeneratedData.characterThoughts ? 'exists' : 'null'
// });
committedTrackerData.userStats = lastGeneratedData.userStats;
committedTrackerData.infoBox = lastGeneratedData.infoBox;
committedTrackerData.characterThoughts = lastGeneratedData.characterThoughts;
console.log('[RPG Companion] AFTER commit - committedTrackerData:', {
userStats: committedTrackerData.userStats ? 'exists' : 'null',
infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
characterThoughts: committedTrackerData.characterThoughts ? 'exists' : 'null'
});
// console.log('[RPG Companion] AFTER commit - committedTrackerData:', {
// userStats: committedTrackerData.userStats ? 'exists' : 'null',
// infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
// characterThoughts: committedTrackerData.characterThoughts ? 'exists' : 'null'
// });
// Reset flag after committing (ready for next cycle)
} else {
console.log('[RPG Companion] 🔄 SWIPE: Using existing committedTrackerData (no commit)');
console.log('[RPG Companion] committedTrackerData:', {
userStats: committedTrackerData.userStats ? 'exists' : 'null',
infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
characterThoughts: committedTrackerData.characterThoughts ? 'exists' : 'null'
});
// console.log('[RPG Companion] 🔄 SWIPE: Using existing committedTrackerData (no commit)');
// console.log('[RPG Companion] committedTrackerData:', {
// userStats: committedTrackerData.userStats ? 'exists' : 'null',
// infoBox: committedTrackerData.infoBox ? 'exists' : 'null',
// characterThoughts: committedTrackerData.characterThoughts ? 'exists' : 'null'
// });
// Reset flag after using it (swipe generation complete, ready for next action)
}
}
+16 -16
View File
@@ -214,9 +214,9 @@ function applyInfoBoxLocks(data, lockedItems) {
* @returns {string} JSON string with locks applied
*/
function applyCharactersLocks(data, lockedItems) {
console.log('[Lock Manager] applyCharactersLocks called');
console.log('[Lock Manager] Locked items:', JSON.stringify(lockedItems, null, 2));
console.log('[Lock Manager] Input data:', JSON.stringify(data, null, 2));
// console.log('[Lock Manager] applyCharactersLocks called');
// console.log('[Lock Manager] Locked items:', JSON.stringify(lockedItems, null, 2));
// console.log('[Lock Manager] Input data:', JSON.stringify(data, null, 2));
// Handle both array format and object format
let characters = Array.isArray(data) ? data : (data.characters || []);
@@ -226,7 +226,7 @@ function applyCharactersLocks(data, lockedItems) {
// Check if entire character is locked (index-based)
if (lockedItems[index] === true) {
console.log('[Lock Manager] Locking entire character by index:', index);
// console.log('[Lock Manager] Locking entire character by index:', index);
return { ...char, locked: true };
}
@@ -235,7 +235,7 @@ function applyCharactersLocks(data, lockedItems) {
if (charLocks === true) {
// Entire character is locked
console.log('[Lock Manager] Locking entire character:', charName);
// console.log('[Lock Manager] Locking entire character:', charName);
return { ...char, locked: true };
} else if (charLocks && typeof charLocks === 'object') {
// Character has field-level locks
@@ -255,14 +255,14 @@ function applyCharactersLocks(data, lockedItems) {
// Check at root level first (backward compatibility)
if (modifiedChar[fieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to field:', `${charName}.${fieldName}`);
// console.log('[Lock Manager] Applying lock to field:', `${charName}.${fieldName}`);
modifiedChar[fieldName] = {
value: modifiedChar[fieldName],
locked: true
};
locked = true;
} else if (modifiedChar[snakeCaseFieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to snake_case field:', `${charName}.${snakeCaseFieldName} (from ${fieldName})`);
// console.log('[Lock Manager] Applying lock to snake_case field:', `${charName}.${snakeCaseFieldName} (from ${fieldName})`);
modifiedChar[snakeCaseFieldName] = {
value: modifiedChar[snakeCaseFieldName],
locked: true
@@ -273,7 +273,7 @@ function applyCharactersLocks(data, lockedItems) {
// Check in nested objects (details, relationship, thoughts)
if (!locked && modifiedChar.details) {
if (modifiedChar.details[fieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to details field:', `${charName}.details.${fieldName}`);
// console.log('[Lock Manager] Applying lock to details field:', `${charName}.details.${fieldName}`);
if (!modifiedChar.details || typeof modifiedChar.details !== 'object') {
modifiedChar.details = {};
} else {
@@ -285,7 +285,7 @@ function applyCharactersLocks(data, lockedItems) {
};
locked = true;
} else if (modifiedChar.details[snakeCaseFieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to details snake_case field:', `${charName}.details.${snakeCaseFieldName} (from ${fieldName})`);
// console.log('[Lock Manager] Applying lock to details snake_case field:', `${charName}.details.${snakeCaseFieldName} (from ${fieldName})`);
if (!modifiedChar.details || typeof modifiedChar.details !== 'object') {
modifiedChar.details = {};
} else {
@@ -302,7 +302,7 @@ function applyCharactersLocks(data, lockedItems) {
// Check in relationship object
if (!locked && modifiedChar.relationship) {
if (modifiedChar.relationship[fieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to relationship field:', `${charName}.relationship.${fieldName}`);
// console.log('[Lock Manager] Applying lock to relationship field:', `${charName}.relationship.${fieldName}`);
modifiedChar.relationship = { ...modifiedChar.relationship };
modifiedChar.relationship[fieldName] = {
value: modifiedChar.relationship[fieldName],
@@ -310,7 +310,7 @@ function applyCharactersLocks(data, lockedItems) {
};
locked = true;
} else if (modifiedChar.relationship[snakeCaseFieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to relationship snake_case field:', `${charName}.relationship.${snakeCaseFieldName} (from ${fieldName})`);
// console.log('[Lock Manager] Applying lock to relationship snake_case field:', `${charName}.relationship.${snakeCaseFieldName} (from ${fieldName})`);
modifiedChar.relationship = { ...modifiedChar.relationship };
modifiedChar.relationship[snakeCaseFieldName] = {
value: modifiedChar.relationship[snakeCaseFieldName],
@@ -323,7 +323,7 @@ function applyCharactersLocks(data, lockedItems) {
// Check in thoughts object
if (!locked && modifiedChar.thoughts) {
if (modifiedChar.thoughts[fieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to thoughts field:', `${charName}.thoughts.${fieldName}`);
// console.log('[Lock Manager] Applying lock to thoughts field:', `${charName}.thoughts.${fieldName}`);
modifiedChar.thoughts = { ...modifiedChar.thoughts };
modifiedChar.thoughts[fieldName] = {
value: modifiedChar.thoughts[fieldName],
@@ -331,7 +331,7 @@ function applyCharactersLocks(data, lockedItems) {
};
locked = true;
} else if (modifiedChar.thoughts[snakeCaseFieldName] !== undefined) {
console.log('[Lock Manager] Applying lock to thoughts snake_case field:', `${charName}.thoughts.${snakeCaseFieldName} (from ${fieldName})`);
// console.log('[Lock Manager] Applying lock to thoughts snake_case field:', `${charName}.thoughts.${snakeCaseFieldName} (from ${fieldName})`);
modifiedChar.thoughts = { ...modifiedChar.thoughts };
modifiedChar.thoughts[snakeCaseFieldName] = {
value: modifiedChar.thoughts[snakeCaseFieldName],
@@ -354,7 +354,7 @@ function applyCharactersLocks(data, lockedItems) {
? JSON.stringify(characters, null, 2)
: JSON.stringify({ ...data, characters }, null, 2);
console.log('[Lock Manager] Output data:', result);
// console.log('[Lock Manager] Output data:', result);
return result;
}
@@ -429,7 +429,7 @@ export function isItemLocked(trackerType, itemPath) {
* @param {boolean} locked - New lock state
*/
export function setItemLock(trackerType, itemPath, locked) {
console.log('[Lock Manager] setItemLock called:', { trackerType, itemPath, locked });
// console.log('[Lock Manager] setItemLock called:', { trackerType, itemPath, locked });
if (!extensionSettings.lockedItems) {
extensionSettings.lockedItems = {};
@@ -459,5 +459,5 @@ export function setItemLock(trackerType, itemPath, locked) {
delete current[finalKey];
}
console.log('[Lock Manager] Locked items after set:', JSON.stringify(extensionSettings.lockedItems, null, 2));
// console.log('[Lock Manager] Locked items after set:', JSON.stringify(extensionSettings.lockedItems, null, 2));
}
+44 -38
View File
@@ -129,7 +129,7 @@ function stripBrackets(text) {
* Helper to log to both console and debug logs array
*/
function debugLog(message, data = null) {
console.log(message, data || '');
// console.log(message, data || '');
if (extensionSettings.debugMode) {
addDebugLog(message, data);
}
@@ -209,30 +209,30 @@ export function parseResponse(responseText) {
}
if (extractedObjects.length > 0) {
console.log(`[RPG Parser] ✓ Found ${extractedObjects.length} raw JSON objects (v3 format)`);
// console.log(`[RPG Parser] ✓ Found ${extractedObjects.length} raw JSON objects (v3 format)`);
debugLog(`[RPG Parser] ✓ Found ${extractedObjects.length} raw JSON objects (v3 format)`);
// First, try to parse as unified JSON structure (new v3.1 format)
if (extractedObjects.length === 1) {
const parsed = repairJSON(extractedObjects[0]);
if (parsed && (parsed.userStats || parsed.infoBox || parsed.characters)) {
console.log('[RPG Parser] ✓ Detected unified JSON structure (v3.1 format)');
// console.log('[RPG Parser] ✓ Detected unified JSON structure (v3.1 format)');
if (parsed.userStats) {
result.userStats = JSON.stringify(parsed.userStats);
console.log('[RPG Parser] ✓ Extracted userStats from unified structure');
// console.log('[RPG Parser] ✓ Extracted userStats from unified structure');
}
if (parsed.infoBox) {
result.infoBox = JSON.stringify(parsed.infoBox);
console.log('[RPG Parser] ✓ Extracted infoBox from unified structure');
// console.log('[RPG Parser] ✓ Extracted infoBox from unified structure');
}
if (parsed.characters) {
result.characterThoughts = JSON.stringify(parsed.characters);
console.log('[RPG Parser] ✓ Extracted characters from unified structure');
// console.log('[RPG Parser] ✓ Extracted characters from unified structure');
}
if (result.userStats || result.infoBox || result.characterThoughts) {
console.log('[RPG Parser] ✓ Returning unified JSON parse results');
// console.log('[RPG Parser] ✓ Returning unified JSON parse results');
debugLog('[RPG Parser] Returning unified JSON parse results');
return result;
}
@@ -242,13 +242,13 @@ export function parseResponse(responseText) {
// Fall back to parsing multiple separate JSON objects (legacy v3.0 format)
for (let idx = 0; idx < extractedObjects.length; idx++) {
const jsonContent = extractedObjects[idx];
console.log(`[RPG Parser] Parsing object ${idx + 1}:`, jsonContent.substring(0, 100) + '...');
console.log(`[RPG Parser] Full object ${idx + 1} length:`, jsonContent.length);
// console.log(`[RPG Parser] Parsing object ${idx + 1}:`, jsonContent.substring(0, 100) + '...');
// console.log(`[RPG Parser] Full object ${idx + 1} length:`, jsonContent.length);
const parsed = repairJSON(jsonContent);
if (parsed) {
console.log(`[RPG Parser] Object ${idx + 1} parsed successfully, keys:`, Object.keys(parsed));
// console.log(`[RPG Parser] Object ${idx + 1} parsed successfully, keys:`, Object.keys(parsed));
// Check if object is wrapped (e.g., {"userStats": {...}})
// Unwrap single-key objects that match our tracker types
@@ -257,22 +257,22 @@ export function parseResponse(responseText) {
const key = Object.keys(parsed)[0];
if (key === 'userStats' || key === 'infoBox' || key === 'characters') {
unwrapped = parsed[key];
console.log(`[RPG Parser] ✓ Unwrapped ${key} object`);
// console.log(`[RPG Parser] ✓ Unwrapped ${key} object`);
}
}
// Detect tracker type by checking for top-level fields
if (unwrapped.stats || unwrapped.status || unwrapped.skills || unwrapped.inventory || unwrapped.quests) {
result.userStats = jsonContent;
console.log('[RPG Parser] ✓ Assigned to User Stats');
// console.log('[RPG Parser] ✓ Assigned to User Stats');
debugLog('[RPG Parser] ✓ Extracted raw JSON User Stats');
} else if (unwrapped.date || unwrapped.location || unwrapped.weather || unwrapped.temperature || unwrapped.time) {
result.infoBox = jsonContent;
console.log('[RPG Parser] ✓ Assigned to Info Box');
// console.log('[RPG Parser] ✓ Assigned to Info Box');
debugLog('[RPG Parser] ✓ Extracted raw JSON Info Box');
} else if (unwrapped.characters || Array.isArray(unwrapped)) {
result.characterThoughts = jsonContent;
console.log('[RPG Parser] ✓ Assigned to Characters');
// console.log('[RPG Parser] ✓ Assigned to Characters');
debugLog('[RPG Parser] ✓ Extracted raw JSON Characters');
} else {
console.warn('[RPG Parser] ⚠️ Could not categorize object with keys:', Object.keys(parsed));
@@ -283,11 +283,11 @@ export function parseResponse(responseText) {
}
if (result.userStats || result.infoBox || result.characterThoughts) {
console.log('[RPG Parser] ✓ Returning raw JSON parse results:', {
hasUserStats: !!result.userStats,
hasInfoBox: !!result.infoBox,
hasCharacters: !!result.characterThoughts
});
// console.log('[RPG Parser] ✓ Returning raw JSON parse results:', {
// hasUserStats: !!result.userStats,
// hasInfoBox: !!result.infoBox,
// hasCharacters: !!result.characterThoughts
// });
debugLog('[RPG Parser] Returning raw JSON parse results');
return result;
} else {
@@ -301,31 +301,31 @@ export function parseResponse(responseText) {
const jsonMatches = [...cleanedResponse.matchAll(jsonBlockRegex)];
if (jsonMatches.length > 0) {
console.log('[RPG Parser] ✓ Found', jsonMatches.length, 'JSON code blocks (v3 format with fences)');
// console.log('[RPG Parser] ✓ Found', jsonMatches.length, 'JSON code blocks (v3 format with fences)');
debugLog('[RPG Parser] ✓ Found JSON code blocks (v3 format), parsing as JSON');
for (let idx = 0; idx < jsonMatches.length; idx++) {
const match = jsonMatches[idx];
const jsonContent = match[1].trim();
console.log(`[RPG Parser] Parsing JSON block ${idx + 1}:`, jsonContent.substring(0, 100) + '...');
// console.log(`[RPG Parser] Parsing JSON block ${idx + 1}:`, jsonContent.substring(0, 100) + '...');
const parsed = repairJSON(jsonContent);
if (parsed) {
console.log(`[RPG Parser] JSON block ${idx + 1} parsed successfully, keys:`, Object.keys(parsed));
// console.log(`[RPG Parser] JSON block ${idx + 1} parsed successfully, keys:`, Object.keys(parsed));
// Detect tracker type by checking for top-level fields
if (parsed.stats || parsed.status || parsed.skills || parsed.inventory || parsed.quests) {
result.userStats = jsonContent;
console.log('[RPG Parser] ✓ Assigned to User Stats');
// console.log('[RPG Parser] ✓ Assigned to User Stats');
debugLog('[RPG Parser] ✓ Extracted JSON User Stats');
} else if (parsed.date || parsed.location || parsed.weather || parsed.temperature || parsed.time) {
result.infoBox = jsonContent;
console.log('[RPG Parser] ✓ Assigned to Info Box');
// console.log('[RPG Parser] ✓ Assigned to Info Box');
debugLog('[RPG Parser] ✓ Extracted JSON Info Box');
} else if (parsed.characters || Array.isArray(parsed)) {
result.characterThoughts = jsonContent;
console.log('[RPG Parser] ✓ Assigned to Characters');
// console.log('[RPG Parser] ✓ Assigned to Characters');
debugLog('[RPG Parser] ✓ Extracted JSON Characters');
} else {
console.warn('[RPG Parser] ⚠️ Could not categorize JSON block with keys:', Object.keys(parsed));
@@ -339,11 +339,11 @@ export function parseResponse(responseText) {
// If we found at least one valid JSON block, return the result
// Mixed formats (some JSON, some text) will still work
if (result.userStats || result.infoBox || result.characterThoughts) {
console.log('[RPG Parser] ✓ Returning JSON code block parse results:', {
hasUserStats: !!result.userStats,
hasInfoBox: !!result.infoBox,
hasCharacters: !!result.characterThoughts
});
// console.log('[RPG Parser] ✓ Returning JSON code block parse results:', {
// hasUserStats: !!result.userStats,
// hasInfoBox: !!result.infoBox,
// hasCharacters: !!result.characterThoughts
// });
debugLog('[RPG Parser] Returning JSON parse results');
return result;
} else {
@@ -500,6 +500,12 @@ export function parseResponse(responseText) {
debugLog('[RPG Parser] Found Characters:', !!result.characterThoughts);
debugLog('[RPG Parser] =======================================================');
// Check if we found at least one section - if not, mark as parsing failure
if (!result.userStats && !result.infoBox && !result.characterThoughts) {
result.parsingFailed = true;
console.error('[RPG Parser] ❌ No tracker data found in response - parsing failed');
}
return result;
} // End parseResponse
@@ -525,25 +531,25 @@ export function parseUserStats(statsText) {
// Extract stats from v3 JSON structure
if (statsData.stats && Array.isArray(statsData.stats)) {
console.log('[RPG Parser] ✓ Extracting stats array, count:', statsData.stats.length);
// console.log('[RPG Parser] ✓ Extracting stats array, count:', statsData.stats.length);
statsData.stats.forEach(stat => {
if (stat.id && typeof stat.value !== 'undefined') {
extensionSettings.userStats[stat.id] = stat.value;
console.log(`[RPG Parser] ✓ Set ${stat.id} = ${stat.value}`);
// console.log(`[RPG Parser] ✓ Set ${stat.id} = ${stat.value}`);
}
});
}
// Extract status
if (statsData.status) {
console.log('[RPG Parser] ✓ Extracting status:', statsData.status);
// console.log('[RPG Parser] ✓ Extracting status:', statsData.status);
if (statsData.status.mood) {
extensionSettings.userStats.mood = statsData.status.mood;
console.log('[RPG Parser] ✓ Set mood =', statsData.status.mood);
// console.log('[RPG Parser] ✓ Set mood =', statsData.status.mood);
}
if (statsData.status.conditions) {
extensionSettings.userStats.conditions = statsData.status.conditions;
console.log('[RPG Parser] ✓ Set conditions =', statsData.status.conditions);
// console.log('[RPG Parser] ✓ Set conditions =', statsData.status.conditions);
}
}
@@ -587,7 +593,7 @@ export function parseUserStats(statsText) {
stored: convertStoredInventory(inv.stored),
assets: convertItems(inv.assets)
};
console.log('[RPG Parser] ✓ Converted v3 inventory:', extensionSettings.userStats.inventory);
// console.log('[RPG Parser] ✓ Converted v3 inventory:', extensionSettings.userStats.inventory);
}
// Extract quests (convert v3 object format to v2 string format)
@@ -609,13 +615,13 @@ export function parseUserStats(statsText) {
? statsData.quests.optional.map(convertQuest)
: []
};
console.log('[RPG Parser] ✓ Converted v3 quests:', extensionSettings.quests);
// console.log('[RPG Parser] ✓ Converted v3 quests:', extensionSettings.quests);
}
// Extract skills if present (store as object, not JSON string)
if (statsData.skills && Array.isArray(statsData.skills)) {
extensionSettings.userStats.skills = statsData.skills;
console.log('[RPG Parser] ✓ Set skills:', extensionSettings.userStats.skills);
// console.log('[RPG Parser] ✓ Set skills:', extensionSettings.userStats.skills);
}
debugLog('[RPG Parser] ✓ Successfully extracted v3 JSON data');
+13 -13
View File
@@ -85,7 +85,7 @@ async function getCharacterCardsInfo() {
// Filter out disabled (muted) members
const disabledMembers = group?.disabled_members || [];
console.log('[RPG Companion] 🔍 Group ID:', selected_group, '| Disabled members:', disabledMembers);
// console.log('[RPG Companion] 🔍 Group ID:', selected_group, '| Disabled members:', disabledMembers);
let characterIndex = 0;
groupMembers.forEach((member) => {
@@ -93,7 +93,7 @@ async function getCharacterCardsInfo() {
// Skip muted characters - check against avatar filename
if (member.avatar && disabledMembers.includes(member.avatar)) {
console.log(`[RPG Companion] ❌ Skipping muted: ${member.name} (${member.avatar})`);
// console.log(`[RPG Companion] ❌ Skipping muted: ${member.name} (${member.avatar})`);
return;
}
@@ -236,16 +236,16 @@ export function generateTrackerExample() {
// Build unified JSON structure with proper wrapper keys
const parts = [];
console.log('[RPG Companion] generateTrackerExample - enabled modules:', {
showUserStats: extensionSettings.showUserStats,
showInfoBox: extensionSettings.showInfoBox,
showCharacterThoughts: extensionSettings.showCharacterThoughts
});
console.log('[RPG Companion] generateTrackerExample - committed data:', {
hasUserStats: !!committedTrackerData.userStats,
hasInfoBox: !!committedTrackerData.infoBox,
hasCharacterThoughts: !!committedTrackerData.characterThoughts
});
// console.log('[RPG Companion] generateTrackerExample - enabled modules:', {
// showUserStats: extensionSettings.showUserStats,
// showInfoBox: extensionSettings.showInfoBox,
// showCharacterThoughts: extensionSettings.showCharacterThoughts
// // });
// console.log('[RPG Companion] generateTrackerExample - committed data:', {
// hasUserStats: !!committedTrackerData.userStats,
// hasInfoBox: !!committedTrackerData.infoBox,
// hasCharacterThoughts: !!committedTrackerData.characterThoughts
// });
if (extensionSettings.showUserStats && committedTrackerData.userStats) {
// Try to parse as JSON first, otherwise treat as text
@@ -285,7 +285,7 @@ export function generateTrackerExample() {
example = '{\n' + parts.join(',\n') + '\n}';
}
console.log('[RPG Companion] generateTrackerExample - result length:', example.length, 'parts:', parts.length);
// console.log('[RPG Companion] generateTrackerExample - result length:', example.length, 'parts:', parts.length);
return example.trim();
}