diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png
deleted file mode 100644
index 26ebefc..0000000
Binary files a/public/android-chrome-192x192.png and /dev/null differ
diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png
deleted file mode 100644
index 7b10f7d..0000000
Binary files a/public/android-chrome-512x512.png and /dev/null differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
deleted file mode 100644
index 2c91d4b..0000000
Binary files a/public/apple-touch-icon.png and /dev/null differ
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
index 2c29f4b..6223e14 100644
Binary files a/public/favicon-16x16.png and b/public/favicon-16x16.png differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
deleted file mode 100644
index e2c03c8..0000000
Binary files a/public/favicon-32x32.png and /dev/null differ
diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index 5fa7f96..0000000
Binary files a/public/favicon.ico and /dev/null differ
diff --git a/public/site.webmanifest b/public/site.webmanifest
deleted file mode 100644
index 45dc8a2..0000000
--- a/public/site.webmanifest
+++ /dev/null
@@ -1 +0,0 @@
-{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
diff --git a/public/test-output.json b/public/test-output.json
new file mode 100644
index 0000000..f10f816
--- /dev/null
+++ b/public/test-output.json
@@ -0,0 +1,84 @@
+{
+ "entries": {
+ "0": {
+ "key": [
+ "setting"
+ ],
+ "keysecondary": [],
+ "comment": "πΊοΈ SETTING [ General Modern Fantasy ]",
+ "content": "\nThis world involves both humans and supernatural creatures coexisting on modern day Earth.\n",
+ "constant": true,
+ "vectorized": false,
+ "selective": true,
+ "selectiveLogic": 0,
+ "addMemo": true,
+ "order": 100,
+ "position": 0,
+ "disable": false,
+ "excludeRecursion": false,
+ "preventRecursion": false,
+ "matchPersonaDescription": false,
+ "matchCharacterDescription": false,
+ "matchCharacterPersonality": false,
+ "matchCharacterDepthPrompt": false,
+ "matchScenario": false,
+ "matchCreatorNotes": false,
+ "delayUntilRecursion": false,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "group": "",
+ "groupOverride": false,
+ "groupWeight": 100,
+ "scanDepth": null,
+ "caseSensitive": null,
+ "matchWholeWords": null,
+ "useGroupScoring": false,
+ "automationId": "",
+ "role": null,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "uid": 0,
+ "displayIndex": 0,
+ "extensions": {
+ "position": 0,
+ "exclude_recursion": false,
+ "display_index": 0,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "selectiveLogic": 0,
+ "group": "",
+ "group_override": false,
+ "group_weight": 100,
+ "prevent_recursion": false,
+ "delay_until_recursion": false,
+ "scan_depth": null,
+ "match_whole_words": null,
+ "use_group_scoring": false,
+ "case_sensitive": null,
+ "automation_id": "",
+ "role": 0,
+ "vectorized": false,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "match_persona_description": false,
+ "match_character_description": false,
+ "match_character_personality": false,
+ "match_character_depth_prompt": false,
+ "match_scenario": false,
+ "match_creator_notes": false
+ },
+ "ignoreBudget": false,
+ "outletName": "",
+ "triggers": [],
+ "characterFilter": {
+ "isExclude": false,
+ "names": [],
+ "tags": []
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 35bad08..38f98a5 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -9,16 +9,7 @@ export const metadata: Metadata = {
description: "Convert Janitor AI lorebook format to SillyTavern format with comprehensive editing capabilities",
icons: {
icon: [
- { url: '/favicon.ico' },
{ url: '/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
- { url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
- ],
- apple: [
- { url: '/apple-touch-icon.png' }
- ],
- other: [
- { url: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' },
- { url: '/android-chrome-512x512.png', sizes: '512x512', type: 'image/png' },
],
},
};
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 91ac037..7e6cc60 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -101,7 +101,7 @@ export default function Home() {
}
setOriginalFileName(file.name.replace('.json', ''));
-
+
const reader = new FileReader();
reader.onload = (e) => {
try {
@@ -130,26 +130,79 @@ export default function Home() {
e.preventDefault();
};
- const convertJanitorToSillyTavern = (janitorData: any[]): ConvertedLorebook => {
- const entries: { [key: string]: LorebookEntry } = {};
+ const convertJanitorToSillyTavern = (janitorData: any[]): any => {
+ const entries: { [key: string]: any } = {};
+ const originalDataEntries: any[] = [];
- janitorData.forEach((entry, uid) => {
- entries[uid.toString()] = {
- uid: entry.id !== undefined ? entry.id : uid,
- key: entry.key || [],
- keysecondary: entry.keysecondary || [],
- comment: entry.comment || entry.name || "Entry",
- content: entry.content || "",
- constant: entry.constant || false,
- vectorized: false,
- selective: entry.selectiveLogic !== undefined ? true : true,
- selectiveLogic: entry.selectiveLogic || 0,
- addMemo: true,
- order: entry.insertion_order || entry.order || 100,
+ janitorData.forEach((entry, index) => {
+ // Handle both integer IDs and UUID IDs
+ const entryId = entry.id;
+ const isIntegerId = typeof entryId === 'number' || (typeof entryId === 'string' && /^\d+$/.test(entryId));
+ const uid = isIntegerId ? (typeof entryId === 'number' ? entryId : parseInt(entryId, 10)) : index;
+ const displayIndex = entry.priority !== undefined ? entry.priority + 20 : (isIntegerId ? uid + 20 : index + 20);
+ const order = entry.insertion_order || entry.order || 100;
+ const probability = entry.probability || 100;
+ const depth = entry.depth || 4;
+ const selectiveLogic = entry.selectiveLogic || 0;
+ const groupWeight = entry.groupWeight || 100;
+ const group = entry.inclusionGroupRaw || "";
+ const caseSensitive = entry.case_sensitive ? true : null;
+ const disable = entry.enabled !== undefined ? !entry.enabled : false;
+ const constant = entry.constant || false;
+ // Strip emojis from comment
+ const rawComment = entry.comment || entry.name || "";
+ const comment = rawComment.replace(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2300}-\u{23FF}]|[\u{2B50}]|[\u{2934}-\u{2935}]|[\u{25AA}-\u{25AB}]|[\u{25B6}]|[\u{25C0}]|[\u{25FB}-\u{25FE}]|[\u{2614}-\u{2615}]|[\u{2648}-\u{2653}]|[\u{267F}]|[\u{2693}]|[\u{26A1}]|[\u{26AA}-\u{26AB}]|[\u{26BD}-\u{26BE}]|[\u{26C4}-\u{26C5}]|[\u{26CE}]|[\u{26D4}]|[\u{26EA}]|[\u{26F2}-\u{26F3}]|[\u{26F5}]|[\u{26FA}]|[\u{26FD}]|[\u{2702}]|[\u{2705}]|[\u{2708}-\u{270D}]|[\u{270F}]|[\u{2712}]|[\u{2714}]|[\u{2716}]|[\u{271D}]|[\u{2721}]|[\u{2728}]|[\u{2733}-\u{2734}]|[\u{2744}]|[\u{2747}]|[\u{274C}]|[\u{274E}]|[\u{2753}-\u{2755}]|[\u{2757}]|[\u{2763}-\u{2764}]|[\u{2795}-\u{2797}]|[\u{27A1}]|[\u{27B0}]|[\u{27BF}]|[\u{2B05}-\u{2B07}]|[\u{2B1B}-\u{2B1C}]|[\u{2B55}]|[\u{3030}]|[\u{303D}]|[\u{3297}]|[\u{3299}]|[\u{FE0F}]|[β β£β₯β¦β€β§β‘β’β¦β§β
ββββββ β‘β²β³βΌβ½ββΆββ·]/gu, '').trim();
+ const keys = entry.key || [];
+ const keysecondary = entry.keysecondary || [];
+ const content = entry.content || "";
+
+ // Build extensions object for both entries and originalData
+ const extensionsObj = {
position: 0,
- disable: entry.enabled !== undefined ? !entry.enabled : false,
- excludeRecursion: true,
- preventRecursion: true,
+ exclude_recursion: !constant,
+ display_index: displayIndex,
+ probability: probability,
+ useProbability: true,
+ depth: depth,
+ selectiveLogic: selectiveLogic,
+ group: group,
+ group_override: false,
+ group_weight: groupWeight,
+ prevent_recursion: !constant,
+ delay_until_recursion: false,
+ scan_depth: null,
+ match_whole_words: null,
+ use_group_scoring: false,
+ case_sensitive: caseSensitive,
+ automation_id: "",
+ role: 0,
+ vectorized: false,
+ sticky: 0,
+ cooldown: 0,
+ delay: 0,
+ match_persona_description: false,
+ match_character_description: false,
+ match_character_personality: false,
+ match_character_depth_prompt: false,
+ match_scenario: false,
+ match_creator_notes: false
+ };
+
+ entries[index.toString()] = {
+ key: keys,
+ keysecondary: keysecondary,
+ comment: comment,
+ content: content,
+ constant: constant,
+ vectorized: false,
+ selective: true,
+ selectiveLogic: selectiveLogic,
+ addMemo: true,
+ order: order,
+ position: 0,
+ disable: disable,
+ excludeRecursion: !constant,
+ preventRecursion: !constant,
matchPersonaDescription: false,
matchCharacterDescription: false,
matchCharacterPersonality: false,
@@ -157,29 +210,57 @@ export default function Home() {
matchScenario: false,
matchCreatorNotes: false,
delayUntilRecursion: false,
- probability: entry.probability || 100,
- useProbability: entry.probability !== undefined,
- depth: entry.depth || 4,
- group: entry.inclusionGroupRaw || entry.category || "",
+ probability: probability,
+ useProbability: true,
+ depth: depth,
+ group: group,
groupOverride: false,
- groupWeight: entry.groupWeight || 100,
+ groupWeight: groupWeight,
scanDepth: null,
- caseSensitive: entry.case_sensitive || false,
- matchWholeWords: entry.matchWholeWords !== undefined ? entry.matchWholeWords : true,
+ caseSensitive: caseSensitive,
+ matchWholeWords: null,
useGroupScoring: false,
automationId: "",
role: null,
sticky: 0,
cooldown: 0,
delay: 0,
- displayIndex: entry.id !== undefined ? entry.id : uid,
- filterToCharacters: "",
- filterToGenerationTriggers: "",
- excludeFromGeneration: false
+ uid: uid,
+ displayIndex: displayIndex,
+ extensions: extensionsObj,
+ ignoreBudget: false,
+ outletName: "",
+ triggers: [],
+ characterFilter: {
+ isExclude: false,
+ names: [],
+ tags: []
+ }
};
+
+ // Add to originalData entries array
+ originalDataEntries.push({
+ id: index,
+ keys: keys,
+ secondary_keys: keysecondary,
+ comment: comment,
+ content: content,
+ constant: constant,
+ selective: true,
+ insertion_order: order,
+ enabled: !disable,
+ position: "before_char",
+ use_regex: true,
+ extensions: extensionsObj
+ });
});
- return { entries };
+ return {
+ entries,
+ originalData: {
+ entries: originalDataEntries
+ }
+ };
};
const downloadLorebook = () => {
@@ -221,10 +302,10 @@ export default function Home() {
const deleteEntry = (entryId: string) => {
if (!convertedData) return;
-
+
const newEntries = { ...convertedData.entries };
delete newEntries[entryId];
-
+
setConvertedData({
...convertedData,
entries: newEntries
@@ -463,7 +544,7 @@ export default function Home() {
{entry.comment}
- UID: {entry.uid} β’ Order: {entry.order} β’
+ UID: {entry.uid} β’ Order: {entry.order} β’
{entry.key.length > 0 ? ` Keys: ${entry.key.join(', ')}` : ' No keys'}
@@ -508,14 +589,14 @@ export default function Home() {
)}
-
+
{entry.group && (
)}
-
+
Content
@@ -531,7 +612,7 @@ export default function Home() {
{entry.content}
-
+
Constant: {entry.constant ? 'Yes' : 'No'}
diff --git a/test-minimal.json b/test-minimal.json
new file mode 100644
index 0000000..ca01610
--- /dev/null
+++ b/test-minimal.json
@@ -0,0 +1,139 @@
+{
+ "entries": {
+ "0": {
+ "key": [
+ "Dean Archer Wolfwood",
+ "human students",
+ "integrated education",
+ "2002"
+ ],
+ "keysecondary": [],
+ "comment": "Founding of SUCC",
+ "content": "\n\nFounding of SUCC\nIn 2002, facing declining supernatural enrollment as young monsters increasingly chose to attend human colleges, visionary Dean Archer Wolfwood made the bold decision to open SUCC's doors to human students for the first time in the school's history. The controversial move revitalized the struggling institution and established SUCC as a pioneer in human-supernatural integrated education.\n\n",
+ "constant": false,
+ "vectorized": false,
+ "selective": true,
+ "selectiveLogic": 0,
+ "addMemo": true,
+ "order": 100,
+ "position": 0,
+ "disable": false,
+ "excludeRecursion": true,
+ "preventRecursion": true,
+ "matchPersonaDescription": false,
+ "matchCharacterDescription": false,
+ "matchCharacterPersonality": false,
+ "matchCharacterDepthPrompt": false,
+ "matchScenario": false,
+ "matchCreatorNotes": false,
+ "delayUntilRecursion": false,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "group": "",
+ "groupOverride": false,
+ "groupWeight": 100,
+ "scanDepth": null,
+ "caseSensitive": null,
+ "matchWholeWords": null,
+ "useGroupScoring": false,
+ "automationId": "",
+ "role": null,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "uid": 0,
+ "displayIndex": 28,
+ "extensions": {
+ "position": 0,
+ "exclude_recursion": true,
+ "display_index": 28,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "selectiveLogic": 0,
+ "group": "",
+ "group_override": false,
+ "group_weight": 100,
+ "prevent_recursion": true,
+ "delay_until_recursion": false,
+ "scan_depth": null,
+ "match_whole_words": null,
+ "use_group_scoring": false,
+ "case_sensitive": null,
+ "automation_id": "",
+ "role": 0,
+ "vectorized": false,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "match_persona_description": false,
+ "match_character_description": false,
+ "match_character_personality": false,
+ "match_character_depth_prompt": false,
+ "match_scenario": false,
+ "match_creator_notes": false
+ },
+ "ignoreBudget": false,
+ "outletName": "",
+ "triggers": [],
+ "characterFilter": {
+ "isExclude": false,
+ "names": [],
+ "tags": []
+ }
+ }
+ },
+ "originalData": {
+ "entries": [
+ {
+ "id": 0,
+ "keys": [
+ "Dean Archer Wolfwood",
+ "human students",
+ "integrated education",
+ "2002"
+ ],
+ "secondary_keys": [],
+ "comment": "Founding of SUCC",
+ "content": "\n\nFounding of SUCC\nIn 2002, facing declining supernatural enrollment as young monsters increasingly chose to attend human colleges, visionary Dean Archer Wolfwood made the bold decision to open SUCC's doors to human students for the first time in the school's history. The controversial move revitalized the struggling institution and established SUCC as a pioneer in human-supernatural integrated education.\n\n",
+ "constant": false,
+ "selective": true,
+ "insertion_order": 100,
+ "enabled": true,
+ "position": "before_char",
+ "use_regex": true,
+ "extensions": {
+ "position": 0,
+ "exclude_recursion": true,
+ "display_index": 28,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "selectiveLogic": 0,
+ "group": "",
+ "group_override": false,
+ "group_weight": 100,
+ "prevent_recursion": true,
+ "delay_until_recursion": false,
+ "scan_depth": null,
+ "match_whole_words": null,
+ "use_group_scoring": false,
+ "case_sensitive": null,
+ "automation_id": "",
+ "role": 0,
+ "vectorized": false,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "match_persona_description": false,
+ "match_character_description": false,
+ "match_character_personality": false,
+ "match_character_depth_prompt": false,
+ "match_scenario": false,
+ "match_creator_notes": false
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/test-output.json b/test-output.json
new file mode 100644
index 0000000..f10f816
--- /dev/null
+++ b/test-output.json
@@ -0,0 +1,84 @@
+{
+ "entries": {
+ "0": {
+ "key": [
+ "setting"
+ ],
+ "keysecondary": [],
+ "comment": "πΊοΈ SETTING [ General Modern Fantasy ]",
+ "content": "\nThis world involves both humans and supernatural creatures coexisting on modern day Earth.\n",
+ "constant": true,
+ "vectorized": false,
+ "selective": true,
+ "selectiveLogic": 0,
+ "addMemo": true,
+ "order": 100,
+ "position": 0,
+ "disable": false,
+ "excludeRecursion": false,
+ "preventRecursion": false,
+ "matchPersonaDescription": false,
+ "matchCharacterDescription": false,
+ "matchCharacterPersonality": false,
+ "matchCharacterDepthPrompt": false,
+ "matchScenario": false,
+ "matchCreatorNotes": false,
+ "delayUntilRecursion": false,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "group": "",
+ "groupOverride": false,
+ "groupWeight": 100,
+ "scanDepth": null,
+ "caseSensitive": null,
+ "matchWholeWords": null,
+ "useGroupScoring": false,
+ "automationId": "",
+ "role": null,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "uid": 0,
+ "displayIndex": 0,
+ "extensions": {
+ "position": 0,
+ "exclude_recursion": false,
+ "display_index": 0,
+ "probability": 100,
+ "useProbability": true,
+ "depth": 4,
+ "selectiveLogic": 0,
+ "group": "",
+ "group_override": false,
+ "group_weight": 100,
+ "prevent_recursion": false,
+ "delay_until_recursion": false,
+ "scan_depth": null,
+ "match_whole_words": null,
+ "use_group_scoring": false,
+ "case_sensitive": null,
+ "automation_id": "",
+ "role": 0,
+ "vectorized": false,
+ "sticky": 0,
+ "cooldown": 0,
+ "delay": 0,
+ "match_persona_description": false,
+ "match_character_description": false,
+ "match_character_personality": false,
+ "match_character_depth_prompt": false,
+ "match_scenario": false,
+ "match_creator_notes": false
+ },
+ "ignoreBudget": false,
+ "outletName": "",
+ "triggers": [],
+ "characterFilter": {
+ "isExclude": false,
+ "names": [],
+ "tags": []
+ }
+ }
+ }
+}
\ No newline at end of file