Fix: Strip thinking tags from parser and persist tracker data on page refresh
- Added removal of <think> and <thinking> tags from AI responses before parsing - Fixed Info Box display to use committedTrackerData as fallback after page refresh - Fixed Present Characters display to use committedTrackerData as fallback after page refresh - Fixed 4-part character format handling in updateCharacterField to preserve thoughts - Ensures Recent Events and all tracker data persist correctly across page reloads
This commit is contained in:
@@ -46,6 +46,31 @@ function separateEmojiFromText(str) {
|
||||
return { emoji: '', text: str };
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to strip enclosing brackets from text
|
||||
* Removes [], {}, and () from the entire text if it's wrapped
|
||||
* @param {string} text - Text that may be wrapped in brackets
|
||||
* @returns {string} Text with brackets removed
|
||||
*/
|
||||
function stripBrackets(text) {
|
||||
if (!text) return text;
|
||||
|
||||
// Remove leading and trailing whitespace first
|
||||
text = text.trim();
|
||||
|
||||
// Check if the entire text is wrapped in brackets and remove them
|
||||
// This handles cases where models wrap entire sections in brackets
|
||||
while (
|
||||
(text.startsWith('[') && text.endsWith(']')) ||
|
||||
(text.startsWith('{') && text.endsWith('}')) ||
|
||||
(text.startsWith('(') && text.endsWith(')'))
|
||||
) {
|
||||
text = text.substring(1, text.length - 1).trim();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to log to both console and debug logs array
|
||||
*/
|
||||
@@ -76,9 +101,15 @@ export function parseResponse(responseText) {
|
||||
debugLog('[RPG Parser] Response length:', responseText.length + ' chars');
|
||||
debugLog('[RPG Parser] First 500 chars:', responseText.substring(0, 500));
|
||||
|
||||
// Remove content inside thinking tags first (model's internal reasoning)
|
||||
// This prevents parsing code blocks from the model's thinking process
|
||||
let cleanedResponse = responseText.replace(/<think>[\s\S]*?<\/think>/gi, '');
|
||||
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, '');
|
||||
debugLog('[RPG Parser] Removed thinking tags, new length:', cleanedResponse.length + ' chars');
|
||||
|
||||
// Extract code blocks
|
||||
const codeBlockRegex = /```([^`]+)```/g;
|
||||
const matches = [...responseText.matchAll(codeBlockRegex)];
|
||||
const matches = [...cleanedResponse.matchAll(codeBlockRegex)];
|
||||
|
||||
debugLog('[RPG Parser] Found', matches.length + ' code blocks');
|
||||
|
||||
@@ -102,21 +133,21 @@ export function parseResponse(responseText) {
|
||||
// Extract User Stats section
|
||||
const statsMatch = content.match(/(User )?Stats\s*\n\s*---[\s\S]*?(?=\n\s*\n\s*(Info Box|Present Characters)|$)/i);
|
||||
if (statsMatch && !result.userStats) {
|
||||
result.userStats = statsMatch[0].trim();
|
||||
result.userStats = stripBrackets(statsMatch[0].trim());
|
||||
debugLog('[RPG Parser] ✓ Extracted Stats from combined block');
|
||||
}
|
||||
|
||||
// Extract Info Box section
|
||||
const infoBoxMatch = content.match(/Info Box\s*\n\s*---[\s\S]*?(?=\n\s*\n\s*Present Characters|$)/i);
|
||||
if (infoBoxMatch && !result.infoBox) {
|
||||
result.infoBox = infoBoxMatch[0].trim();
|
||||
result.infoBox = stripBrackets(infoBoxMatch[0].trim());
|
||||
debugLog('[RPG Parser] ✓ Extracted Info Box from combined block');
|
||||
}
|
||||
|
||||
// Extract Present Characters section
|
||||
const charactersMatch = content.match(/Present Characters\s*\n\s*---[\s\S]*$/i);
|
||||
if (charactersMatch && !result.characterThoughts) {
|
||||
result.characterThoughts = charactersMatch[0].trim();
|
||||
result.characterThoughts = stripBrackets(charactersMatch[0].trim());
|
||||
debugLog('[RPG Parser] ✓ Extracted Present Characters from combined block');
|
||||
}
|
||||
} else {
|
||||
@@ -146,13 +177,13 @@ export function parseResponse(responseText) {
|
||||
(content.includes(" | ") && (content.includes("Thoughts") || content.includes("💭")));
|
||||
|
||||
if (isStats && !result.userStats) {
|
||||
result.userStats = content;
|
||||
result.userStats = stripBrackets(content);
|
||||
debugLog('[RPG Parser] ✓ Matched: Stats section');
|
||||
} else if (isInfoBox && !result.infoBox) {
|
||||
result.infoBox = content;
|
||||
result.infoBox = stripBrackets(content);
|
||||
debugLog('[RPG Parser] ✓ Matched: Info Box section');
|
||||
} else if (isCharacters && !result.characterThoughts) {
|
||||
result.characterThoughts = content;
|
||||
result.characterThoughts = stripBrackets(content);
|
||||
debugLog('[RPG Parser] ✓ Matched: Present Characters section');
|
||||
debugLog('[RPG Parser] Full content:', content);
|
||||
} else {
|
||||
|
||||
@@ -64,8 +64,11 @@ export function renderInfoBox() {
|
||||
$infoBoxContainer.addClass('rpg-content-updating');
|
||||
}
|
||||
|
||||
// Use committedTrackerData as fallback if lastGeneratedData is empty (e.g., after page refresh)
|
||||
const infoBoxData = lastGeneratedData.infoBox || committedTrackerData.infoBox;
|
||||
|
||||
// If no data yet, show placeholder
|
||||
if (!lastGeneratedData.infoBox) {
|
||||
if (!infoBoxData) {
|
||||
const placeholderHtml = `
|
||||
<div class="rpg-dashboard rpg-dashboard-row-1">
|
||||
<div class="rpg-dashboard-widget rpg-placeholder-widget">
|
||||
@@ -81,10 +84,10 @@ export function renderInfoBox() {
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log('[RPG Companion] renderInfoBox called with data:', lastGeneratedData.infoBox);
|
||||
// console.log('[RPG Companion] renderInfoBox called with data:', infoBoxData);
|
||||
|
||||
// Parse the info box data
|
||||
const lines = lastGeneratedData.infoBox.split('\n');
|
||||
const lines = infoBoxData.split('\n');
|
||||
// console.log('[RPG Companion] Info Box split into lines:', lines);
|
||||
const data = {
|
||||
date: '',
|
||||
|
||||
@@ -76,15 +76,13 @@ export function renderThoughts() {
|
||||
$thoughtsContainer.addClass('rpg-content-updating');
|
||||
}
|
||||
|
||||
// Initialize if no data yet
|
||||
if (!lastGeneratedData.characterThoughts) {
|
||||
lastGeneratedData.characterThoughts = '';
|
||||
}
|
||||
// Use committedTrackerData as fallback if lastGeneratedData is empty (e.g., after page refresh)
|
||||
const characterThoughtsData = lastGeneratedData.characterThoughts || committedTrackerData.characterThoughts || '';
|
||||
|
||||
debugLog('[RPG Thoughts] Raw characterThoughts data:', lastGeneratedData.characterThoughts);
|
||||
debugLog('[RPG Thoughts] Data length:', lastGeneratedData.characterThoughts.length + ' chars');
|
||||
debugLog('[RPG Thoughts] Raw characterThoughts data:', characterThoughtsData);
|
||||
debugLog('[RPG Thoughts] Data length:', characterThoughtsData.length + ' chars');
|
||||
|
||||
const lines = lastGeneratedData.characterThoughts.split('\n');
|
||||
const lines = characterThoughtsData.split('\n');
|
||||
const presentCharacters = [];
|
||||
|
||||
debugLog('[RPG Thoughts] Split into lines count:', lines.length);
|
||||
@@ -378,8 +376,14 @@ export function updateCharacterField(characterName, field, value) {
|
||||
if (emojiMatch) {
|
||||
let emoji = emojiMatch[1].trim();
|
||||
let info = emojiMatch[2].trim();
|
||||
let relationship = parts[1];
|
||||
let thoughts = parts[2] || '';
|
||||
let relationship = parts[1] ? parts[1].trim() : '';
|
||||
let thoughts = parts[2] ? parts[2].trim() : '';
|
||||
|
||||
// Handle 4-part format (with demeanor)
|
||||
if (parts.length >= 4) {
|
||||
relationship = parts[2] ? parts[2].trim() : '';
|
||||
thoughts = parts[3] ? parts[3].trim() : '';
|
||||
}
|
||||
|
||||
const infoParts = info.split(',').map(p => p.trim());
|
||||
let name = infoParts[0];
|
||||
|
||||
Reference in New Issue
Block a user