feat: add optional prompt metadata saving to chat messages (#848)
# PR Checklist - [ ] Have you checked if it works normally in all models? *Ignore this if it doesn't use models.* - [x] Have you checked if it works normally in all web, local, and node hosted versions? If it doesn't, have you blocked it in those versions? - [x] Have you added type definitions? # Description ## What does this PR do? This PR adds an optional feature to store prompt preset metadata in each chat message. <img width="311" alt="prompt" src="https://github.com/user-attachments/assets/2591ac25-6cb2-41fc-85b2-e12c35b79370" /> --- ## Why is this useful? When writing prompts, it's common to test **dozens of prompt presets** across many messages. After just a day or two, it's hard to remember which message used which prompt. This is especially important for sensitive models, where even small changes to prompt wording or toggle combinations can greatly affect output. --- ## What is stored when enabled? To support this, an option has been added to **Advanced Settings** that stores: - Prompt preset name (*Add Prompt Info to Chat*) - Active custom toggles (*Add Prompt Info to Chat*) - Prompt text (*Add Prompt *Text* To Chat*): Only the **Prompt Template** portion of the final prompt (**as sent**) is stored — character description, persona, lorebook, and long-term memory are excluded to avoid excessive size. This option is separated due to its potential impact on storage. This information is stored per message, if the feature is enabled. <img width="319" alt="setting" src="https://github.com/user-attachments/assets/00600d0c-d38d-46cf-890f-3f08d78ccb0a" /> --- ## Implementation Summary ### `src/ts/storage/database.svelte.ts` - Added `interface MessagePresetInfo` (includes `promptName`, `promptToggles`, `promptText`) - Updated `interface Message` with optional `promptInfo` ### `src/ts/process/index.svelte.ts` - In `sendChat()`, prompt metadata is collected and stored - `promptText` is taken from the existing `formated` array, but only after filtering out types like `'persona'`, `'description'`, `'authornote'`, `'memory'` - Since `formated` is reused, this had to be placed in the **later** part of the `sendChat` function. - However, `promptName` and `promptToggles` are collected **early** to avoid mismatches caused by user changes during message sending. *(A short comment has been added to explain the code separation. See screenshot below.)* <img width="494" alt="comment" src="https://github.com/user-attachments/assets/b43da333-d529-4b3c-b659-579b847135a5" /> - Used this condition when storing partial prompt data (As you can see, these are the types that support Custom Inner Format.): ```ts // only for types supporting Custom Inner Format if (DBState.db.promptInfoInsideChat && DBState.db.promptTextInfoInsideChat) { pushPromptInfoBody('supaMemory', card.innerFormat) } ``` - The final `promptInfo` is added to the message object during `message.push` --- ## Additional Notes - The prompt preset name and active toggles take up very little space, so they are unlikely to be an issue. - The prompt text may increase the message size slightly, but: - Modern models already generate outputs of several thousand tokens, so adding \~2,000 tokens of metadata is relatively minor in comparison. - The `{{slot}}` contents are not included in the saved text. - The prompt text is filtered through `risuChatParser`, which reduces unnecessary parts before saving. - Most importantly, this feature is optional and can be enabled only by those who need it — for example, prompt creators or advanced users. --- ## Final Thoughts This feature is designed to help prompt creators **track, debug, and revisit** messages more easily. If this feature doesn't fit the project goals or introduces any concerns, feel free to let me know or suggest changes. It might also be interesting to allow users to write a note for each message! Thanks for reading.
This commit is contained in:
@@ -176,6 +176,7 @@ export const languageEnglish = {
|
||||
comfyWorkflow: "Put the API workflow of comfy UI. you can get your API workflow in comfy UI by pressing the 'Workflow > Export (API)' button. you must also put {{risu_prompt}} in you workflow text. the {{risu_prompt}} will be replaced with the prompt provided by the Risu.",
|
||||
automaticCachePoint: "Automatically creates cache point after the chat ends, if the caching point doesn't exist.",
|
||||
experimentalChatCompressionDesc: "Compresses the unused chat data and saves in seperate file. this greatly reduces the size of the chat data, and greatly improves the performance, however its experimental and can be unstable, causing issues in backup feature and more.",
|
||||
promptInfoInsideChatDesc: "When enabled, this stores prompt preset information in the chat metadata. The stored data includes the preset name, active toggles, and the prompt text. This may slightly increase processing time and storage usage.",
|
||||
},
|
||||
setup: {
|
||||
chooseProvider: "Choose AI Provider",
|
||||
@@ -1122,4 +1123,9 @@ export const languageEnglish = {
|
||||
hypaMemoryV2Modal: "Hypa V2 Modal",
|
||||
hypaMemoryV3Modal: "Hypa V3 Modal",
|
||||
showMenuHypaMemoryModal: "Show Menu Hypa Modal",
|
||||
promptInfoInsideChat: "Add Prompt Info to Chat",
|
||||
promptTextInfoInsideChat: "Add Prompt Text to Chat",
|
||||
promptInfoEmptyMessage: "No prompt information is available for this message.",
|
||||
promptInfoEmptyToggle: "No custom toggles are currently active.",
|
||||
promptInfoEmptyText: "No prompt text has been saved.",
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ export const languageKorean = {
|
||||
"groupOtherBotRole": "This defines a role that is used in group chat for characters that isn't speaker.",
|
||||
"chatHTML": "A HTML that would be inserted as each chat.\n\nYou can use CBS and special tags.\n- `<risutextbox>`: a textbox that would be used to render text\n- `<risuicon>`: an icon for user or assistant\n- `<risubuttons>`: icon buttons for chat edit, translations and etc.\n- `<risugeninfo>`: generation information button.",
|
||||
"autoTranslateCachedOnly": "자동 번역 옵션이 켜진 상태에서 활성화하면, 사용자가 이전에 번역한 메시지만 자동으로 번역됩니다.",
|
||||
"promptInfoInsideChatDesc": "활성화되면 채팅 메타데이터에 프롬프트 프리셋 정보를 저장합니다. 저장되는 정보는 프롬프트 프리셋 이름과 활성화된 토글, 그리고 프롬프트 텍스트입니다. 약간의 처리 시간과 용량을 차지할 수 있습니다.",
|
||||
},
|
||||
"setup": {
|
||||
"chooseProvider": "AI 제공자를 선택해 주세요",
|
||||
@@ -989,4 +990,9 @@ export const languageKorean = {
|
||||
"hypaMemoryV2Modal": "하이파 V2 모달",
|
||||
"hypaMemoryV3Modal": "하이파 V3 모달",
|
||||
"showMenuHypaMemoryModal": "메뉴에서 하이파 모달 보이기",
|
||||
"promptInfoInsideChat": "채팅에 프롬프트 정보 추가하기",
|
||||
"promptTextInfoInsideChat": "채팅에 프롬프트 텍스트 정보 추가하기",
|
||||
"promptInfoEmptyMessage": "이 메시지에 대한 프롬프트 정보가 없습니다.",
|
||||
"promptInfoEmptyToggle": "활성화된 커스텀 토글이 없습니다.",
|
||||
"promptInfoEmptyText": "저장된 프롬프트 텍스트가 없습니다.",
|
||||
}
|
||||
|
||||
@@ -225,6 +225,9 @@
|
||||
<Button selected={generationInfoMenuIndex === 2} size="sm" onclick={() => {generationInfoMenuIndex = 2}}>
|
||||
{language.log}
|
||||
</Button>
|
||||
<Button selected={generationInfoMenuIndex === 3} size="sm" onclick={() => {generationInfoMenuIndex = 3}}>
|
||||
{language.prompt}
|
||||
</Button>
|
||||
<button class="ml-auto" onclick={() => {
|
||||
alertStore.set({
|
||||
type: 'none',
|
||||
@@ -295,6 +298,42 @@
|
||||
{/if}
|
||||
{/await}
|
||||
{/if}
|
||||
{#if generationInfoMenuIndex === 3}
|
||||
{#if Object.keys(DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message[$alertGenerationInfoStore.idx].promptInfo || {}).length === 0}
|
||||
<div class="text-gray-300 text-lg mt-2">{language.promptInfoEmptyMessage}</div>
|
||||
{:else}
|
||||
<div class="grid grid-cols-2 gap-y-2 gap-x-4 mt-4">
|
||||
<span class="text-blue-500">Preset Name</span>
|
||||
<span class="text-blue-500 justify-self-end">{DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message[$alertGenerationInfoStore.idx].promptInfo.promptName}</span>
|
||||
<span class="text-purple-500">Toggles</span>
|
||||
<div class="col-span-2 max-h-32 overflow-y-auto border border-stone-500 rounded p-2 bg-gray-900">
|
||||
{#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message[$alertGenerationInfoStore.idx].promptInfo.promptToggles.length === 0}
|
||||
<div class="text-gray-500 italic text-center py-4">{language.promptInfoEmptyToggle}</div>
|
||||
{:else}
|
||||
<div class="grid grid-cols-2 gap-y-2 gap-x-4">
|
||||
{#each DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message[$alertGenerationInfoStore.idx].promptInfo.promptToggles as toggle}
|
||||
<span class="text-gray-200 truncate">{toggle.key}</span>
|
||||
<span class="text-gray-200 justify-self-end truncate">{toggle.value}</span>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<span class="text-red-500">Prompt Text</span>
|
||||
<div class="col-span-2 max-h-80 overflow-y-auto border border-stone-500 rounded p-4 bg-gray-900">
|
||||
{#if !DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message[$alertGenerationInfoStore.idx].promptInfo.promptText}
|
||||
<div class="text-gray-500 italic text-center py-4">{language.promptInfoEmptyText}</div>
|
||||
{:else}
|
||||
{#each DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message[$alertGenerationInfoStore.idx].promptInfo.promptText as block}
|
||||
<div class="mb-2">
|
||||
<div class="font-bold text-gray-600">{block.role}</div>
|
||||
<pre class="whitespace-pre-wrap text-sm bg-stone-900 p-2 rounded border border-stone-500">{block.content}</pre>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{:else if $alertStore.type === 'hypaV2'}
|
||||
<div class="flex flex-wrap gap-2 mb-4 max-w-full w-124">
|
||||
<Button selected={generationInfoMenuIndex === 0} size="sm" onclick={() => {generationInfoMenuIndex = 0}}>
|
||||
|
||||
@@ -190,6 +190,17 @@
|
||||
<Check bind:check={DBState.db.enableDevTools} name={language.enableDevTools}>
|
||||
</Check>
|
||||
</div>
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={DBState.db.promptInfoInsideChat} name={language.promptInfoInsideChat}>
|
||||
<Help key="promptInfoInsideChatDesc"/>
|
||||
</Check>
|
||||
</div>
|
||||
{#if DBState.db.promptInfoInsideChat}
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={DBState.db.promptTextInfoInsideChat} name={language.promptTextInfoInsideChat}>
|
||||
</Check>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex items-center mt-4">
|
||||
<Check bind:check={DBState.db.dynamicAssets} name={language.dynamicAssets}>
|
||||
<Help key="dynamicAssets"/>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { get, writable } from "svelte/store";
|
||||
import { type character, type MessageGenerationInfo, type Chat, changeToPreset, setCurrentChat } from "../storage/database.svelte";
|
||||
import { type character, type MessageGenerationInfo, type Chat, type MessagePresetInfo, changeToPreset, setCurrentChat } from "../storage/database.svelte";
|
||||
import { DBState } from '../stores.svelte';
|
||||
import { CharEmotion, selectedCharID } from "../stores.svelte";
|
||||
import { ChatTokenizer, tokenize, tokenizeNum } from "../tokenizer";
|
||||
import { language } from "../../lang";
|
||||
import { alertError, alertToast } from "../alert";
|
||||
import { loadLoreBookV3Prompt } from "./lorebook.svelte";
|
||||
import { findCharacterbyId, getAuthorNoteDefaultText, getPersonaPrompt, getUserName, isLastCharPunctuation, trimUntilPunctuation } from "../util";
|
||||
import { findCharacterbyId, getAuthorNoteDefaultText, getPersonaPrompt, getUserName, isLastCharPunctuation, trimUntilPunctuation, parseToggleSyntax } from "../util";
|
||||
import { requestChatData } from "./request";
|
||||
import { stableDiff } from "./stableDiff";
|
||||
import { processScript, processScriptFull, risuChatParser } from "./scripts";
|
||||
@@ -30,7 +30,7 @@ import { runLuaEditTrigger } from "./lua";
|
||||
import { getGlobalChatVar, parseChatML } from "../parser.svelte";
|
||||
import { getModelInfo, LLMFlags } from "../model/modellist";
|
||||
import { hypaMemoryV3 } from "./memory/hypav3";
|
||||
import { getModuleAssets } from "./modules";
|
||||
import { getModuleAssets, getModuleToggles } from "./modules";
|
||||
import { getFileSrc, readImage } from "../globalApi.svelte";
|
||||
|
||||
export interface OpenAIChat{
|
||||
@@ -186,6 +186,39 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
return v
|
||||
})
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// Snapshot preset name & toggles before sending a message.
|
||||
// Ensures correct metadata is recorded, even if presets
|
||||
// change immediately after clicking "send".
|
||||
//
|
||||
// Used later in promptInfo assembly (e.g. promptInfo.promptText)
|
||||
// ─────────────────────────────────────────────────────────
|
||||
let promptInfo: MessagePresetInfo = {}
|
||||
let initialPresetNameForPromptInfo = null
|
||||
let initialPromptTogglesForPromptInfo: {
|
||||
key: string,
|
||||
value: string,
|
||||
}[] = []
|
||||
if(DBState.db.promptInfoInsideChat){
|
||||
initialPresetNameForPromptInfo = DBState.db.botPresets[DBState.db.botPresetsId]?.name ?? ''
|
||||
initialPromptTogglesForPromptInfo = parseToggleSyntax(DBState.db.customPromptTemplateToggle + getModuleToggles())
|
||||
.flatMap(toggle => {
|
||||
const raw = DBState.db.globalChatVariables[`toggle_${toggle.key}`]
|
||||
if (toggle.type === 'select' || toggle.type === 'text') {
|
||||
return [{ key: toggle.value, value: toggle.options[raw] }];
|
||||
}
|
||||
if (raw === '1') {
|
||||
return [{ key: toggle.value, value: 'ON' }];
|
||||
}
|
||||
return [];
|
||||
})
|
||||
|
||||
promptInfo = {
|
||||
promptName: initialPresetNameForPromptInfo,
|
||||
promptToggles: initialPromptTogglesForPromptInfo,
|
||||
}
|
||||
}
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
let currentChar:character
|
||||
let caculatedChatTokens = 0
|
||||
@@ -367,13 +400,15 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
if(currentChat.note){
|
||||
unformated.authorNote.push({
|
||||
role: 'system',
|
||||
content: risuChatParser(currentChat.note, {chara: currentChar})
|
||||
content: risuChatParser(currentChat.note, {chara: currentChar}),
|
||||
memo: 'authornote'
|
||||
})
|
||||
}
|
||||
else if(getAuthorNoteDefaultText() !== ''){
|
||||
unformated.authorNote.push({
|
||||
role: 'system',
|
||||
content: risuChatParser(getAuthorNoteDefaultText(), {chara: currentChar})
|
||||
content: risuChatParser(getAuthorNoteDefaultText(), {chara: currentChar}),
|
||||
memo: 'authornote'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -403,7 +438,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
|
||||
unformated.description.push({
|
||||
role: 'system',
|
||||
content: description
|
||||
content: description,
|
||||
memo: 'description',
|
||||
})
|
||||
|
||||
if(nowChatroom.type === 'group'){
|
||||
@@ -424,7 +460,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
for(const lorebook of normalActives){
|
||||
unformated.lorebook.push({
|
||||
role: lorebook.role,
|
||||
content: risuChatParser(lorebook.prompt, {chara: currentChar})
|
||||
content: risuChatParser(lorebook.prompt, {chara: currentChar}),
|
||||
memo: 'lore',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -448,7 +485,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
if(DBState.db.personaPrompt){
|
||||
unformated.personaPrompt.push({
|
||||
role: 'system',
|
||||
content: risuChatParser(getPersonaPrompt(), {chara: currentChar})
|
||||
content: risuChatParser(getPersonaPrompt(), {chara: currentChar}),
|
||||
memo: 'persona',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -473,7 +511,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
for(const lorebook of postEverythingLorebooks){
|
||||
unformated.postEverything.push({
|
||||
role: lorebook.role,
|
||||
content: risuChatParser(lorebook.prompt, {chara: currentChar})
|
||||
content: risuChatParser(lorebook.prompt, {chara: currentChar}),
|
||||
memo: 'postEverything',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1061,6 +1100,12 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
}
|
||||
}
|
||||
|
||||
type MemoType = 'persona' | 'description' | 'authornote' | 'supaMemory';
|
||||
const promptBodyMap: Record<MemoType, string[]> = { persona: [], description: [], authornote: [], supaMemory: [] };
|
||||
function pushPromptInfoBody(memo: MemoType, fmt: string) {
|
||||
promptBodyMap[memo].push(risuChatParser(fmt));
|
||||
}
|
||||
|
||||
if(promptTemplate){
|
||||
const template = promptTemplate
|
||||
|
||||
@@ -1071,6 +1116,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
if(card.innerFormat && pmt.length > 0){
|
||||
for(let i=0;i<pmt.length;i++){
|
||||
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content)
|
||||
|
||||
if(DBState.db.promptInfoInsideChat && DBState.db.promptTextInfoInsideChat){
|
||||
pushPromptInfoBody(card.type, card.innerFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,6 +1131,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
if(card.innerFormat && pmt.length > 0){
|
||||
for(let i=0;i<pmt.length;i++){
|
||||
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content)
|
||||
|
||||
if(DBState.db.promptInfoInsideChat && DBState.db.promptTextInfoInsideChat){
|
||||
pushPromptInfoBody(card.type, card.innerFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1093,6 +1146,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
if(card.innerFormat && pmt.length > 0){
|
||||
for(let i=0;i<pmt.length;i++){
|
||||
pmt[i].content = risuChatParser(positionParser(card.innerFormat), {chara: currentChar}).replace('{{slot}}', pmt[i].content || card.defaultText || '')
|
||||
|
||||
if(DBState.db.promptInfoInsideChat && DBState.db.promptTextInfoInsideChat){
|
||||
pushPromptInfoBody(card.type, card.innerFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,6 +1265,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
if(card.innerFormat && pmt.length > 0){
|
||||
for(let i=0;i<pmt.length;i++){
|
||||
pmt[i].content = risuChatParser(card.innerFormat, {chara: currentChar}).replace('{{slot}}', pmt[i].content)
|
||||
|
||||
if(DBState.db.promptInfoInsideChat && DBState.db.promptTextInfoInsideChat){
|
||||
pushPromptInfoBody('supaMemory', card.innerFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1327,6 +1388,29 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
function isPromptMemo(m: string): m is MemoType {
|
||||
return ['persona', 'description', 'authornote', 'supaMemory'].includes(m);
|
||||
}
|
||||
if(DBState.db.promptInfoInsideChat && DBState.db.promptTextInfoInsideChat){
|
||||
const promptBodyInfo: OpenAIChat[] = formated.flatMap(format => {
|
||||
if (isPromptMemo(format.memo)) {
|
||||
return promptBodyMap[format.memo].map(content => ({
|
||||
role: format.role,
|
||||
content,
|
||||
}))
|
||||
}
|
||||
|
||||
if (format.memo == null) {
|
||||
return [format]
|
||||
}
|
||||
|
||||
return []
|
||||
})
|
||||
|
||||
promptInfo.promptText = promptBodyInfo
|
||||
}
|
||||
|
||||
let result = ''
|
||||
let emoChanged = false
|
||||
let resendChat = false
|
||||
@@ -1353,6 +1437,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
saying: currentChar.chaId,
|
||||
time: Date.now(),
|
||||
generationInfo,
|
||||
promptInfo,
|
||||
})
|
||||
}
|
||||
DBState.db.characters[selectedChar].chats[selectedChat].isStreaming = true
|
||||
@@ -1432,7 +1517,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
data: result,
|
||||
saying: currentChar.chaId,
|
||||
time: Date.now(),
|
||||
generationInfo
|
||||
generationInfo,
|
||||
promptInfo,
|
||||
}
|
||||
if(inlayResult.promise){
|
||||
const p = await inlayResult.promise
|
||||
@@ -1445,7 +1531,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{
|
||||
data: result,
|
||||
saying: currentChar.chaId,
|
||||
time: Date.now(),
|
||||
generationInfo
|
||||
generationInfo,
|
||||
promptInfo,
|
||||
})
|
||||
const ind = DBState.db.characters[selectedChar].chats[selectedChat].message.length - 1
|
||||
if(inlayResult.promise){
|
||||
|
||||
@@ -1026,6 +1026,8 @@ export interface Database{
|
||||
igpPrompt:string
|
||||
useTokenizerCaching:boolean
|
||||
showMenuHypaMemoryModal:boolean
|
||||
promptInfoInsideChat:boolean
|
||||
promptTextInfoInsideChat:boolean
|
||||
}
|
||||
|
||||
interface SeparateParameters{
|
||||
@@ -1504,6 +1506,7 @@ export interface Message{
|
||||
chatId?:string
|
||||
time?: number
|
||||
generationInfo?: MessageGenerationInfo
|
||||
promptInfo?: MessagePresetInfo
|
||||
name?:string
|
||||
otherUser?:boolean
|
||||
}
|
||||
@@ -1516,6 +1519,12 @@ export interface MessageGenerationInfo{
|
||||
maxContext?: number
|
||||
}
|
||||
|
||||
export interface MessagePresetInfo{
|
||||
promptName?: string,
|
||||
promptToggles?: {key: string, value: string}[],
|
||||
promptText?: OpenAIChat[],
|
||||
}
|
||||
|
||||
interface AINsettings{
|
||||
top_p: number,
|
||||
rep_pen: number,
|
||||
@@ -1882,6 +1891,7 @@ import type { Parameter } from '../process/request';
|
||||
import type { HypaModel } from '../process/memory/hypamemory';
|
||||
import type { SerializableHypaV3Data } from '../process/memory/hypav3';
|
||||
import { defaultHotkeys, type Hotkey } from '../defaulthotkeys';
|
||||
import type { OpenAIChat } from '../process/index.svelte';
|
||||
|
||||
export async function downloadPreset(id:number, type:'json'|'risupreset'|'return' = 'json'){
|
||||
saveCurrentPreset()
|
||||
|
||||
Reference in New Issue
Block a user