Migrate only unique and non-default instruct prompts
| @@ -219,6 +219,37 @@ function getContentIndex() { | ||
| 219 | 219 | } |
| 220 | 220 | |
| 221 | 221 | /** |
| 222 | + * Gets content by type and format. | |
| 223 | + * @param {string} type Type of content | |
| 224 | + * @param {'json'|'string'|'raw'} format Format of content | |
| 225 | + * @returns {string[]|Buffer[]} Array of content | |
| 226 | + */ | |
| 227 | +function getContentOfType(type, format) { | |
| 228 | + const contentIndex = getContentIndex(); | |
| 229 | + const indexItems = contentIndex.filter((item) => item.type === type && item.folder); | |
| 230 | + const files = []; | |
| 231 | + for (const item of indexItems) { | |
| 232 | + if (!item.folder) { | |
| 233 | + continue; | |
| 234 | + } | |
| 235 | + const filePath = path.join(item.folder, item.filename); | |
| 236 | + const fileContent = fs.readFileSync(filePath); | |
| 237 | + switch (format) { | |
| 238 | + case 'json': | |
| 239 | + files.push(JSON.parse(fileContent.toString())); | |
| 240 | + break; | |
| 241 | + case 'string': | |
| 242 | + files.push(fileContent.toString()); | |
| 243 | + break; | |
| 244 | + case 'raw': | |
| 245 | + files.push(fileContent); | |
| 246 | + break; | |
| 247 | + } | |
| 248 | + } | |
| 249 | + return files; | |
| 250 | +} | |
| 251 | + | |
| 252 | +/** | |
| 222 | 253 | * Gets the target directory for the specified asset type. |
| 223 | 254 | * @param {ContentType} type Asset type |
| 224 | 255 | * @param {import('../users').UserDirectoryList} directories User directories |
| @@ -724,5 +755,6 @@ module.exports = { | ||
| 724 | 755 | checkForNewContent, |
| 725 | 756 | getDefaultPresets, |
| 726 | 757 | getDefaultPresetFile, |
| 758 | + getContentOfType, | |
| 727 | 759 | router, |
| 728 | 760 | }; |
| @@ -10,6 +10,7 @@ const express = require('express'); | ||
| 10 | 10 | const mime = require('mime-types'); |
| 11 | 11 | const archiver = require('archiver'); |
| 12 | 12 | const writeFileAtomicSync = require('write-file-atomic').sync; |
| 13 | +const _ = require('lodash'); | |
| 13 | 14 | |
| 14 | 15 | const { USER_DIRECTORY_TEMPLATE, DEFAULT_USER, PUBLIC_DIRECTORIES, SETTINGS_FILE } = require('./constants'); |
| 15 | 16 | const { getConfigValue, color, delay, setConfigValue, generateTimestamp } = require('./util'); |
| @@ -326,6 +327,19 @@ async function migrateUserData() { | ||
| 326 | 327 | } |
| 327 | 328 | |
| 328 | 329 | async function migrateSystemPrompts() { |
| 330 | + /** | |
| 331 | + * Gets the default system prompts. | |
| 332 | + * @returns {Promise<any[]>} - The list of default system prompts | |
| 333 | + */ | |
| 334 | + async function getDefaultSystemPrompts() { | |
| 335 | + try { | |
| 336 | + const { getContentOfType } = await import('./endpoints/content-manager.js'); | |
| 337 | + return getContentOfType('sysprompt', 'json'); | |
| 338 | + } catch { | |
| 339 | + return []; | |
| 340 | + } | |
| 341 | + } | |
| 342 | + | |
| 329 | 343 | const directories = await getUserDirectoriesList(); |
| 330 | 344 | for (const directory of directories) { |
| 331 | 345 | try { |
| @@ -333,21 +347,31 @@ async function migrateSystemPrompts() { | ||
| 333 | 347 | if (fs.existsSync(migrateMarker)) { |
| 334 | 348 | continue; |
| 335 | 349 | } |
| 350 | + const defaultPrompts = await getDefaultSystemPrompts(); | |
| 336 | 351 | const instucts = fs.readdirSync(directory.instruct); |
| 352 | + let migratedPrompts = []; | |
| 337 | 353 | for (const instruct of instucts) { |
| 338 | 354 | const instructPath = path.join(directory.instruct, instruct); |
| 339 | 355 | const syspromptPathsysPromptPath = path.join(directory.sysprompt, instruct); |
| 340 | 356 | if (path.extname(instruct) === '.json' && !fs.existsSync(syspromptPathsysPromptPath)) { |
| 341 | 357 | const instructData = JSON.parse(fs.readFileSync(instructPath, 'utf8')); |
| 342 | 358 | if ('system_prompt' in instructData && 'name' in instructData) { |
| 343 | 359 | const syspromptData = { name: instructData.name, content: instructData.system_prompt }; |
| 344 | - writeFileAtomicSync(syspromptPath, JSON.stringify(syspromptData, null, 4)); | |
| 360 | + migratedPrompts.push(syspromptData); | |
| 345 | 361 | delete instructData.system_prompt; |
| 346 | 362 | writeFileAtomicSync(instructPath, JSON.stringify(instructData, null, 4)); |
| 347 | - console.log(`Migrated system prompt ${instruct} for ${directory.root.split(path.sep).pop()}`); | |
| 348 | 363 | } |
| 349 | 364 | } |
| 350 | 365 | } |
| 366 | + // Only leave unique contents | |
| 367 | + migratedPrompts = _.uniqBy(migratedPrompts, 'content'); | |
| 368 | + // Only leave contents that are not in the default prompts | |
| 369 | + migratedPrompts = migratedPrompts.filter(x => !defaultPrompts.some(y => y.content === x.content)); | |
| 370 | + for (const sysPromptData of migratedPrompts) { | |
| 371 | + const syspromptPath = path.join(directory.sysprompt, `${sysPromptData.name}.json`); | |
| 372 | + writeFileAtomicSync(syspromptPath, JSON.stringify(sysPromptData, null, 4)); | |
| 373 | + console.log(`Migrated system prompt ${sysPromptData.name} for ${directory.root.split(path.sep).pop()}`); | |
| 374 | + } | |
| 351 | 375 | writeFileAtomicSync(migrateMarker, ''); |
| 352 | 376 | } catch { |
| 353 | 377 | // Ignore errors |