diff --git a/.prettierrc b/.prettierrc index 2639eeb91..54b87c590 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "printWidth": 120, + "printWidth": 100, "semi": false, "trailingComma": "es5", "singleQuote": true, diff --git a/common/adapters.ts b/common/adapters.ts index 621c12da7..77b2c0a69 100644 --- a/common/adapters.ts +++ b/common/adapters.ts @@ -237,7 +237,16 @@ export const adapterSettings: { gaslight: ['openai', 'novel', 'scale', 'kobold', 'claude', 'ooba', 'goose', 'openrouter'], systemPrompt: ['openai', 'novel', 'scale', 'kobold', 'claude', 'ooba', 'goose', 'openrouter'], - ignoreCharacterSystemPrompt: ['openai', 'novel', 'scale', 'kobold', 'claude', 'ooba', 'goose', 'openrouter'], + ignoreCharacterSystemPrompt: [ + 'openai', + 'novel', + 'scale', + 'kobold', + 'claude', + 'ooba', + 'goose', + 'openrouter', + ], ultimeJailbreak: ['openai', 'claude', 'kobold', 'scale', 'openrouter'], ignoreCharacterUjb: ['openai', 'claude', 'kobold', 'openrouter'], diff --git a/common/characters.ts b/common/characters.ts index 2f0f79a5e..567294091 100644 --- a/common/characters.ts +++ b/common/characters.ts @@ -20,7 +20,10 @@ export const defaultChars = { "*A soft smile appears on {{char}}'s face as {{user}} enters the cafe and takes a seat* *Beep! Boop!* Hello, {{user}}! It's good to see you again. What would you like to chat about?", }, } satisfies { - [key: string]: Pick + [key: string]: Pick< + AppSchema.Character, + 'name' | 'persona' | 'sampleChat' | 'scenario' | 'greeting' + > } export function exportCharacter(char: AppSchema.Character, target: 'tavern' | 'ooba') { @@ -53,7 +56,9 @@ export function exportCharacter(char: AppSchema.Character, target: 'tavern' | 'o system_prompt: char.systemPrompt ?? '', post_history_instructions: char.postHistoryInstructions ?? '', alternate_greetings: char.alternateGreetings ?? [], - character_book: char.characterBook ? nativeToCharacterBook(char.characterBook) : undefined, + character_book: char.characterBook + ? nativeToCharacterBook(char.characterBook) + : undefined, tags: char.tags ?? [], creator: char.creator ?? '', character_version: char.characterVersion ?? '', @@ -80,7 +85,11 @@ export function exportCharacter(char: AppSchema.Character, target: 'tavern' | 'o } } -export function formatCharacter(name: string, persona: AppSchema.Persona, kind?: AppSchema.Persona['kind']) { +export function formatCharacter( + name: string, + persona: AppSchema.Persona, + kind?: AppSchema.Persona['kind'] +) { switch (kind || persona.kind) { case 'wpp': { const attrs = Object.entries(persona.attributes) @@ -91,7 +100,9 @@ export function formatCharacter(name: string, persona: AppSchema.Persona, kind?: } case 'sbf': { - const attrs = Object.entries(persona.attributes).map(([key, values]) => `${key}: ${values.map(quote).join(', ')}`) + const attrs = Object.entries(persona.attributes).map( + ([key, values]) => `${key}: ${values.map(quote).join(', ')}` + ) return `[ character: "${name}"; ${attrs.join('; ')} ]` } diff --git a/common/default-preset.ts b/common/default-preset.ts index f2bfe170c..a4111681b 100644 --- a/common/default-preset.ts +++ b/common/default-preset.ts @@ -75,7 +75,9 @@ export const altJailbreak = ` export const cyoaTemplate = (model?: string) => { const jailbreak = - model === OPENAI_MODELS.Turbo0613 || model === OPENAI_MODELS.Turbo ? modernJailbreak : originalJailbreak + model === OPENAI_MODELS.Turbo0613 || model === OPENAI_MODELS.Turbo + ? modernJailbreak + : originalJailbreak return ` Recent conversation history: {{history}} diff --git a/common/dummy.ts b/common/dummy.ts index 20625d672..b4ebdfee6 100644 --- a/common/dummy.ts +++ b/common/dummy.ts @@ -3,7 +3,10 @@ import { AppSchema } from './types/schema' let counter = Date.now() -export function toChar(name: string, overrides?: Partial): AppSchema.Character { +export function toChar( + name: string, + overrides?: Partial +): AppSchema.Character { return { _id: name, kind: 'character', @@ -130,7 +133,12 @@ export function toBook(name: string, entries: AppSchema.MemoryEntry[] = []): App } } -export function toEntry(keywords: string[], entry: string, priority = 0, weight = 0): AppSchema.MemoryEntry { +export function toEntry( + keywords: string[], + entry: string, + priority = 0, + weight = 0 +): AppSchema.MemoryEntry { return { enabled: true, name: entry, diff --git a/common/guidance/guidance-parser.ts b/common/guidance/guidance-parser.ts index b9bbc20ca..21f8e9506 100644 --- a/common/guidance/guidance-parser.ts +++ b/common/guidance/guidance-parser.ts @@ -166,7 +166,12 @@ function handlePipe(value: string, pipe?: Pipe) { case 'words': { const [first] = value.trim().split('\n') - const words = first.replace(/\n/g, ' ').split(' ').slice(0, pipe.value).join(' ').replace(/\./gi, '') + const words = first + .replace(/\n/g, ' ') + .split(' ') + .slice(0, pipe.value) + .join(' ') + .replace(/\./gi, '') return words } } diff --git a/common/horde-gen.ts b/common/horde-gen.ts index 44a749604..a62fd1fd9 100644 --- a/common/horde-gen.ts +++ b/common/horde-gen.ts @@ -22,7 +22,9 @@ type FetchOpts = { key?: string } -type Fetcher = (opts: FetchOpts) => Promise<{ statusCode?: number; statusMessage?: string; body: T }> +type Fetcher = ( + opts: FetchOpts +) => Promise<{ statusCode?: number; statusMessage?: string; body: T }> type HordeCheck = { generations: any[] @@ -147,7 +149,10 @@ export async function generateText( top_k: preset.topK ?? defaultPresets.horde.topK, top_p: preset.topP ?? defaultPresets.horde.topP, typical: preset.typicalP ?? defaultPresets.horde.typicalP, - max_context_length: Math.min(preset.maxContextLength ?? defaultPresets.horde.maxContextLength, 2048), + max_context_length: Math.min( + preset.maxContextLength ?? defaultPresets.horde.maxContextLength, + 2048 + ), rep_pen: preset.repetitionPenalty ?? defaultPresets.horde.repetitionPenaltyRange, rep_pen_range: preset.repetitionPenaltyRange ?? defaultPresets.horde.repetitionPenaltyRange, rep_pen_slope: preset.repetitionPenaltySlope, @@ -178,7 +183,9 @@ async function generate(opts: GenerateOpts) { if (init.statusCode && init.statusCode >= 400) { const error: any = new Error( - `Failed to create Horde generation ${init.statusCode} ${init.body.message || init.statusMessage}` + `Failed to create Horde generation ${init.statusCode} ${ + init.body.message || init.statusMessage + }` ) error.body = init.body throw error @@ -213,7 +220,9 @@ async function poll(url: string, key: string | undefined, interval = 6.5) { const res = await useFetch({ method: 'get', url, key }) if (res.statusCode && res.statusCode >= 400) { - const error: any = new Error(`Horde request failed (${res.statusCode}) ${res.body.message || res.statusMessage}`) + const error: any = new Error( + `Horde request failed (${res.statusCode}) ${res.body.message || res.statusMessage}` + ) error.body = res.body throw error } diff --git a/common/image-prompt.ts b/common/image-prompt.ts index c9accf447..55df13d9d 100644 --- a/common/image-prompt.ts +++ b/common/image-prompt.ts @@ -13,7 +13,10 @@ export type ImagePromptOpts = { const appearanceKeys = ['appearance', 'looks'] -export async function createAppearancePrompt(user: AppSchema.User, avatar: { persona: AppSchema.Persona }) { +export async function createAppearancePrompt( + user: AppSchema.User, + avatar: { persona: AppSchema.Persona } +) { let visuals: string[] = [] const max = getMaxImageContext(user) diff --git a/common/image.ts b/common/image.ts index 965b1909f..7a86d8a51 100644 --- a/common/image.ts +++ b/common/image.ts @@ -59,6 +59,9 @@ type ReverseMap> = { } function reverseKeyValue(obj: T): ReverseMap { - const reversed = Object.entries(obj).reduce((prev, [key, value]) => Object.assign(prev, { [value]: key }), {}) + const reversed = Object.entries(obj).reduce( + (prev, [key, value]) => Object.assign(prev, { [value]: key }), + {} + ) return reversed as any } diff --git a/common/memory.ts b/common/memory.ts index 5d8bd154d..1b8bb9770 100644 --- a/common/memory.ts +++ b/common/memory.ts @@ -57,7 +57,9 @@ export type CharacterBook = { selective?: boolean /** if `true`, require a key from both `keys` and `secondary_keys` to trigger the entry */ secondary_keys?: Array /** see field `selective`. ignored if selective == false */ constant?: boolean /** if true, always inserted in the prompt (within budget limit) */ - position?: 'before_char' | 'after_char' /** whether the entry is placed before or after the character defs */ + position?: + | 'before_char' + | 'after_char' /** whether the entry is placed before or after the character defs */ }> } @@ -149,7 +151,10 @@ export function buildMemoryPrompt(opts: MemoryOpts, encoder: Encoder): MemoryPro } } -function byPriorityThenIndex({ id: lid, index: li, entry: l }: Match, { id: rid, index: ri, entry: r }: Match) { +function byPriorityThenIndex( + { id: lid, index: li, entry: l }: Match, + { id: rid, index: ri, entry: r }: Match +) { if (l.weight !== r.weight) return l.weight < r.weight ? 1 : -1 if (li !== ri) return li > ri ? -1 : 1 return lid > rid ? 1 : lid === rid ? 0 : -1 diff --git a/common/prompt.ts b/common/prompt.ts index 4ebb4af1e..4e135055e 100644 --- a/common/prompt.ts +++ b/common/prompt.ts @@ -1,6 +1,12 @@ import type { GenerateRequestV2 } from '../srv/adapter/type' import type { AppSchema } from './types/schema' -import { AIAdapter, NOVEL_MODELS, OPENAI_CHAT_MODELS, OPENAI_MODELS, SUPPORTS_INSTRUCT } from './adapters' +import { + AIAdapter, + NOVEL_MODELS, + OPENAI_CHAT_MODELS, + OPENAI_MODELS, + SUPPORTS_INSTRUCT, +} from './adapters' import { formatCharacter } from './characters' import { defaultTemplate } from './default-preset' import { IMAGE_SUMMARY_PROMPT } from './image' @@ -182,7 +188,12 @@ export function createPrompt(opts: PromptOpts, encoder: Encoder, maxContext?: nu * @param lines Always in time-ascending order (oldest to newest) * @returns */ -export function createPromptWithParts(opts: GenerateRequestV2, parts: PromptParts, lines: string[], encoder: Encoder) { +export function createPromptWithParts( + opts: GenerateRequestV2, + parts: PromptParts, + lines: string[], + encoder: Encoder +) { const post = createPostPrompt(opts) const template = getTemplate(opts, parts) const history = { lines, order: 'asc' } as const @@ -197,7 +208,10 @@ export function createPromptWithParts(opts: GenerateRequestV2, parts: PromptPart return { lines: history.lines, prompt, parts, post } } -export function getTemplate(opts: Pick, parts: PromptParts) { +export function getTemplate( + opts: Pick, + parts: PromptParts +) { const isChat = OPENAI_CHAT_MODELS[opts.settings?.oaiModel || ''] ?? false const useGaslight = (opts.settings?.service === 'openai' && isChat) || opts.settings?.useGaslight const gaslight = opts.settings?.gaslight || defaultPresets.openai.gaslight @@ -215,7 +229,10 @@ type InjectOpts = { encoder: Encoder } -export function injectPlaceholders(template: string, { opts, parts, history: hist, encoder, ...rest }: InjectOpts) { +export function injectPlaceholders( + template: string, + { opts, parts, history: hist, encoder, ...rest }: InjectOpts +) { const profile = opts.members.find((mem) => mem.userId === opts.chat.userId) const sender = opts.impersonate?.name || profile?.handle || 'You' @@ -225,7 +242,9 @@ export function injectPlaceholders(template: string, { opts, parts, history: his const next = hist.lines.filter((line) => !line.includes(SAMPLE_CHAT_MARKER)) const postSample = - opts.settings?.service && SUPPORTS_INSTRUCT[opts.settings.service] ? SAMPLE_CHAT_MARKER : '' + opts.settings?.service && SUPPORTS_INSTRUCT[opts.settings.service] + ? SAMPLE_CHAT_MARKER + : '' const msg = `${SAMPLE_CHAT_PREAMBLE}\n${sampleChat}\n${postSample}` .replace(BOT_REPLACE, opts.replyAs.name) @@ -421,7 +440,9 @@ export function getPromptParts(opts: PromptPartsOptions, lines: string[], encode if (!bot) continue if (personalities.has(bot._id)) continue personalities.add(bot._id) - parts.allPersonas.push(`${bot.name}'s personality: ${formatCharacter(bot.name, bot.persona, bot.persona.kind)}`) + parts.allPersonas.push( + `${bot.name}'s personality: ${formatCharacter(bot.name, bot.persona, bot.persona.kind)}` + ) } if (chat.scenario && chat.overrides) { @@ -434,7 +455,9 @@ export function getPromptParts(opts: PromptPartsOptions, lines: string[], encode } parts.sampleChat = ( - replyAs._id === char._id && !!chat.overrides ? chat.sampleChat ?? replyAs.sampleChat : replyAs.sampleChat + replyAs._id === char._id && !!chat.overrides + ? chat.sampleChat ?? replyAs.sampleChat + : replyAs.sampleChat ) .split('\n') .filter(removeEmpty) @@ -513,7 +536,16 @@ function getSupplementaryParts(opts: PromptPartsOptions, replyAs: AppSchema.Char function createPostPrompt( opts: Pick< PromptOpts, - 'kind' | 'chat' | 'char' | 'members' | 'continue' | 'settings' | 'user' | 'book' | 'replyAs' | 'impersonate' + | 'kind' + | 'chat' + | 'char' + | 'members' + | 'continue' + | 'settings' + | 'user' + | 'book' + | 'replyAs' + | 'impersonate' > ) { const post = [] @@ -578,7 +610,12 @@ function getLinesForPrompt( return lines } -export function fillPromptWithLines(encoder: Encoder, tokenLimit: number, amble: string, lines: string[]) { +export function fillPromptWithLines( + encoder: Encoder, + tokenLimit: number, + amble: string, + lines: string[] +) { let count = encoder(amble) const adding: string[] = [] @@ -626,7 +663,8 @@ export function getChatPreset( // #1 if (chat.genPreset) { - if (isDefaultPreset(chat.genPreset)) return { _id: chat.genPreset, ...defaultPresets[chat.genPreset] } + if (isDefaultPreset(chat.genPreset)) + return { _id: chat.genPreset, ...defaultPresets[chat.genPreset] } const preset = userPresets.find((preset) => preset._id === chat.genPreset) if (preset) return preset @@ -671,7 +709,8 @@ export function getAdapter( config: AppSchema.User, preset: Partial | undefined ) { - const chatAdapter = !chat.adapter || chat.adapter === 'default' ? config.defaultAdapter : chat.adapter + const chatAdapter = + !chat.adapter || chat.adapter === 'default' ? config.defaultAdapter : chat.adapter let adapter = preset?.service ? preset.service : chatAdapter @@ -719,8 +758,13 @@ export function getAdapter( * When we know the maximum context limit for a particular LLM, ensure that the context limit we use does not exceed it. */ -function getContextLimit(gen: Partial | undefined, adapter: AIAdapter, model: string): number { - const configuredMax = gen?.maxContextLength || getFallbackPreset(adapter)?.maxContextLength || 2048 +function getContextLimit( + gen: Partial | undefined, + adapter: AIAdapter, + model: string +): number { + const configuredMax = + gen?.maxContextLength || getFallbackPreset(adapter)?.maxContextLength || 2048 const genAmount = gen?.maxTokens || getFallbackPreset(adapter)?.maxTokens || 80 diff --git a/common/template-parser.ts b/common/template-parser.ts index 1f62594dd..e0795a547 100644 --- a/common/template-parser.ts +++ b/common/template-parser.ts @@ -171,7 +171,9 @@ function renderIterator(holder: IterableHolder, children: CNode[], opts: ParseOp const output: string[] = [] const entities = - holder === 'bots' ? Object.values(opts.characters).filter((b) => !!b && b._id !== opts.replyAs._id) : opts.lines + holder === 'bots' + ? Object.values(opts.characters).filter((b) => !!b && b._id !== opts.replyAs._id) + : opts.lines let i = 0 for (const entity of entities) { @@ -231,7 +233,11 @@ function getPlaceholder(node: PlaceHolder | ConditionNode, opts: ParseOpts) { return opts.replyAs.name case 'user': - return opts.impersonate?.name || opts.members.find((m) => m.userId === opts.user._id)?.handle || 'You' + return ( + opts.impersonate?.name || + opts.members.find((m) => m.userId === opts.user._id)?.handle || + 'You' + ) case 'example_dialogue': return opts.parts.sampleChat?.join('\n') || '' diff --git a/common/types/schema.ts b/common/types/schema.ts index 69db67e32..422a094ab 100644 --- a/common/types/schema.ts +++ b/common/types/schema.ts @@ -1,4 +1,10 @@ -import type { AIAdapter, ChatAdapter, OpenRouterModel, PersonaFormat, RegisteredAdapter } from '../adapters' +import type { + AIAdapter, + ChatAdapter, + OpenRouterModel, + PersonaFormat, + RegisteredAdapter, +} from '../adapters' import type { GenerationPreset } from '../presets' import type { ImageSettings } from './image-schema' import type { TTSSettings, VoiceSettings } from './texttospeech-schema' diff --git a/common/types/sprite.ts b/common/types/sprite.ts index 7644c856b..20b11c658 100644 --- a/common/types/sprite.ts +++ b/common/types/sprite.ts @@ -64,7 +64,9 @@ export const emotions = { }, } satisfies SpriteEmote -export const classifyEmotes = Object.keys(emotions).filter((emote) => emote !== 'blink') as EmoteType[] +export const classifyEmotes = Object.keys(emotions).filter( + (emote) => emote !== 'blink' +) as EmoteType[] export type SpriteAttr = | 'accessories' diff --git a/common/types/texttospeech-schema.ts b/common/types/texttospeech-schema.ts index 1f69fa35c..770cee864 100644 --- a/common/types/texttospeech-schema.ts +++ b/common/types/texttospeech-schema.ts @@ -38,6 +38,12 @@ export type NovelTtsSettings = { seed?: string } -export type SpecificVoiceSetting = Extract - -export type VoiceSettingForm = Omit, 'service' | 'voiceId'> +export type SpecificVoiceSetting = Extract< + VoiceSettings, + { service: T } +> + +export type VoiceSettingForm = Omit< + SpecificVoiceSetting, + 'service' | 'voiceId' +> diff --git a/common/util.ts b/common/util.ts index 8ad2d2694..308c049b6 100644 --- a/common/util.ts +++ b/common/util.ts @@ -17,7 +17,8 @@ export function cycleArray(arr: T[], shiftAmount: number) { return [...arr.slice(effectiveShift), ...arr.slice(0, effectiveShift)] } -export const dateStringFromUnix = (unixTimestamp: number): string => new Date(unixTimestamp).toISOString() +export const dateStringFromUnix = (unixTimestamp: number): string => + new Date(unixTimestamp).toISOString() export function uniqBy(arr: T[], accessor: (el: T) => U) { return arr.flatMap((el, i) => (arr.slice(0, i).map(accessor).includes(accessor(el)) ? [] : [el])) @@ -33,7 +34,9 @@ export function toDuration(valueSecs: number, full?: boolean) { } = toRawDuration(valueSecs) if (full) { - return [`${days}d`, `${hours}h`, `${minutes}m`, `${seconds}s`].filter((time) => !time.startsWith('0')).join(':') + return [`${days}d`, `${hours}h`, `${minutes}m`, `${seconds}s`] + .filter((time) => !time.startsWith('0')) + .join(':') } if (days) { diff --git a/common/valid/types.ts b/common/valid/types.ts index 29b702e15..a5a7bc6fe 100644 --- a/common/valid/types.ts +++ b/common/valid/types.ts @@ -56,7 +56,11 @@ export type FromPrimitve = T extends 'string' ? unknown : never -export type FromTuple = T extends [infer U] | readonly [infer U] | [infer U, '?'] | readonly [infer U, '?'] +export type FromTuple = T extends + | [infer U] + | readonly [infer U] + | [infer U, '?'] + | readonly [infer U, '?'] ? U extends Primitive ? T extends [U, '?'] | readonly [U, '?'] ? Array> | undefined diff --git a/common/valid/util.ts b/common/valid/util.ts index 5fff000f2..de8162e96 100644 --- a/common/valid/util.ts +++ b/common/valid/util.ts @@ -3,12 +3,22 @@ import { OptionalPrimitive, Primitive, Validator } from './types' export function isPrimitive(value: any): value is Primitive { return ( typeof value === 'string' && - (value === 'string' || value === 'boolean' || value === 'number' || value === 'any' || value === 'unknown') + (value === 'string' || + value === 'boolean' || + value === 'number' || + value === 'any' || + value === 'unknown') ) } export function isOptionalPrimitive(value: any): value is OptionalPrimitive { - return value === 'string?' || value === 'boolean?' || value === 'number?' || value === 'any?' || value === 'unknown?' + return ( + value === 'string?' || + value === 'boolean?' || + value === 'number?' || + value === 'any?' || + value === 'unknown?' + ) } export function isTuplePrimitive(value: any): value is [Primitive] | readonly [Primitive] { @@ -18,7 +28,9 @@ export function isTuplePrimitive(value: any): value is [Primitive] | readonly [P return true } -export function isTupleOptional(value: any): value is [OptionalPrimitive] | readonly [OptionalPrimitive] { +export function isTupleOptional( + value: any +): value is [OptionalPrimitive] | readonly [OptionalPrimitive] { if (Array.isArray(value) === false) return false if (value.length !== 1) return false if (!isOptionalPrimitive(value[0])) return false @@ -44,7 +56,9 @@ export function isTupleBody( return typeof value[0] === 'object' } -export function isOptionalUnion(value: any): value is T[] | readonly string[] | undefined { +export function isOptionalUnion( + value: any +): value is T[] | readonly string[] | undefined { if (!Array.isArray(value)) return false if (value.length < 1) return false if (isPrimitive(value[0])) return false diff --git a/common/valid/validate.ts b/common/valid/validate.ts index 155ccae12..2578221cc 100644 --- a/common/valid/validate.ts +++ b/common/valid/validate.ts @@ -27,7 +27,10 @@ export function assertValid( } } -export function isValidPartial(type: T, compare: any): compare is Partial> { +export function isValidPartial( + type: T, + compare: any +): compare is Partial> { const errors = validateBody(type, compare, { notThrow: true, partial: true }) return errors.length === 0 } @@ -78,7 +81,8 @@ export function validateBody( const actual = bodyType.slice(0, -1) if (actual === 'any' || actual === 'unknown') continue - if (typeof value !== actual) errors.push(`.${prop} is ${typeof value}, expected ${actual} or undefined`) + if (typeof value !== actual) + errors.push(`.${prop} is ${typeof value}, expected ${actual} or undefined`) continue } diff --git a/package.json b/package.json index ba662eb5b..df966411b 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "build:server": "tsc -p srv.tsconfig.json", "build:watch": "tsc -p srv.tsconfig.json -w", "format": "prettier --check \"web/**/*.tsx\" \"web/**/*.ts\" \"web/**/*.css\" \"web/**/*.html\" && prettier --check \"srv/**/*.ts\"", - "format:fix": "prettier \"web/**/*.ts\" \"web/**/*.tsx\" --write && prettier \"srv/**/*.ts\" --write && prettier \"common/**/*.ts\" --write", + "format:fix": "prettier \"web/**/*.css\" \"web/**/*.ts\" \"web/**/*.tsx\" --write && prettier \"srv/**/*.ts\" --write && prettier \"common/**/*.ts\" --write", "model:init": "python3 -m venv ./.model && .model/bin/pip install poetry==1.4.1 && .model/bin/poetry config virtualenvs.in-project true && npm run model:deps", "model:deps": ".model/bin/poetry install --no-interaction --no-ansi || exit 0", "model:start": ".model/bin/poetry run python model/app.py", diff --git a/srv/adapter/chat-completion.ts b/srv/adapter/chat-completion.ts index 839caef80..3970c7c5e 100644 --- a/srv/adapter/chat-completion.ts +++ b/srv/adapter/chat-completion.ts @@ -3,7 +3,13 @@ import { AdapterProps } from './type' import { OPENAI_MODELS } from '/common/adapters' import { defaultPresets } from '/common/default-preset' import { IMAGE_SUMMARY_PROMPT } from '/common/image' -import { BOT_REPLACE, SAMPLE_CHAT_MARKER, SELF_REPLACE, ensureValidTemplate, injectPlaceholders } from '/common/prompt' +import { + BOT_REPLACE, + SAMPLE_CHAT_MARKER, + SELF_REPLACE, + ensureValidTemplate, + injectPlaceholders, +} from '/common/prompt' import { AppSchema } from '/common/types' import { escapeRegex } from '/common/util' @@ -38,7 +44,10 @@ export function toChatCompletionPayload(opts: AdapterProps, maxTokens: number): const handle = opts.impersonate?.name || opts.sender?.handle || 'You' const gaslight = injectPlaceholders( - ensureValidTemplate(gen.gaslight || defaultPresets.openai.gaslight, opts.parts, ['history', 'post']), + ensureValidTemplate(gen.gaslight || defaultPresets.openai.gaslight, opts.parts, [ + 'history', + 'post', + ]), { opts, parts, @@ -121,7 +130,10 @@ export function toChatCompletionPayload(opts: AdapterProps, maxTokens: number): export function splitSampleChat(opts: SplitSampleChatProps) { const { sampleChat, char, sender, budget } = opts - const regex = new RegExp(`(?<=\\n)(?=${escapeRegex(char)}:|${escapeRegex(sender)}:|System:|)`, 'gi') + const regex = new RegExp( + `(?<=\\n)(?=${escapeRegex(char)}:|${escapeRegex(sender)}:|System:|)`, + 'gi' + ) const additions: CompletionItem[] = [] let tokens = 0 @@ -143,7 +155,11 @@ export function splitSampleChat(opts: SplitSampleChatProps) { } const sample = trimmed.toLowerCase().startsWith('system:') ? trimmed.slice(7).trim() : trimmed - const role = sample.startsWith(char + ':') ? 'assistant' : sample.startsWith(sender + ':') ? 'user' : 'system' + const role = sample.startsWith(char + ':') + ? 'assistant' + : sample.startsWith(sender + ':') + ? 'user' + : 'system' const msg: CompletionItem = { role: role, @@ -160,7 +176,10 @@ export function splitSampleChat(opts: SplitSampleChatProps) { return { additions, consumed: tokens } } -function getPostInstruction(opts: AdapterProps, messages: CompletionItem[]): CompletionItem | undefined { +function getPostInstruction( + opts: AdapterProps, + messages: CompletionItem[] +): CompletionItem | undefined { let prefix = opts.parts.ujb ? `${opts.parts.ujb}\n\n` : '' prefix = injectPlaceholders(prefix, { @@ -215,7 +234,10 @@ function getPostInstruction(opts: AdapterProps, messages: CompletionItem[]): Com function getCharLooks(char: AppSchema.Character) { if (char.persona?.kind === 'text') return - const visuals = [char.persona?.attributes?.looks || '', char.persona?.attributes?.appearance || ''].filter((v) => !!v) + const visuals = [ + char.persona?.attributes?.looks || '', + char.persona?.attributes?.appearance || '', + ].filter((v) => !!v) if (!visuals.length) return return `${char.name}'s appearance: ${visuals.join(', ')}` diff --git a/srv/adapter/claude.ts b/srv/adapter/claude.ts index 3c18e8b5e..a19c29c65 100644 --- a/srv/adapter/claude.ts +++ b/srv/adapter/claude.ts @@ -72,7 +72,11 @@ export const handleClaude: ModelAdapter = async function* (opts) { } const useThirdPartyPassword = base.changed && isThirdParty && user.thirdPartyPassword - const apiKey = useThirdPartyPassword ? user.thirdPartyPassword : !isThirdParty ? user.claudeApiKey : null + const apiKey = useThirdPartyPassword + ? user.thirdPartyPassword + : !isThirdParty + ? user.claudeApiKey + : null const key = !!guest ? apiKey : apiKey ? decryptText(apiKey!) : null if (key) { @@ -134,7 +138,13 @@ function getBaseUrl(user: AppSchema.User, isThirdParty?: boolean) { return { url: baseUrl, changed: false } } -const requestFullCompletion: CompletionGenerator = async function* (url, body, headers, _userId, log) { +const requestFullCompletion: CompletionGenerator = async function* ( + url, + body, + headers, + _userId, + log +) { const resp = await needle('post', url, JSON.stringify(body), { json: true, headers, @@ -224,7 +234,10 @@ function createClaudePrompt(opts: AdapterProps): string { const maxResponseTokens = gen.maxTokens ?? defaultPresets.claude.maxTokens const gaslight = injectPlaceholders( - ensureValidTemplate(gen.gaslight || defaultPresets.claude.gaslight, opts.parts, ['history', 'post']), + ensureValidTemplate(gen.gaslight || defaultPresets.claude.gaslight, opts.parts, [ + 'history', + 'post', + ]), { opts, parts, @@ -243,7 +256,11 @@ function createClaudePrompt(opts: AdapterProps): string { }) const maxBudget = - maxContextLength - maxResponseTokens - gaslightCost - encoder()(ujb) - encoder()(opts.replyAs.name + ':') + maxContextLength - + maxResponseTokens - + gaslightCost - + encoder()(ujb) - + encoder()(opts.replyAs.name + ':') let tokens = 0 const history: string[] = [] @@ -275,7 +292,9 @@ function createClaudePrompt(opts: AdapterProps): string { } const continueAddon = - opts.kind === 'continue' ? `\n\nHuman: Continue ${replyAs.name}'s reply.` : '' + opts.kind === 'continue' + ? `\n\nHuman: Continue ${replyAs.name}'s reply.` + : '' // return messages.join('\n\n') + continueAddon + '\n\n' + 'Assistant: ' + replyAs.name + ':' diff --git a/srv/adapter/generate.ts b/srv/adapter/generate.ts index 2daba0685..29316a960 100644 --- a/srv/adapter/generate.ts +++ b/srv/adapter/generate.ts @@ -1,5 +1,10 @@ import { AIAdapter } from '../../common/adapters' -import { mapPresetsToAdapter, defaultPresets, isDefaultPreset, getFallbackPreset } from '/common/presets' +import { + mapPresetsToAdapter, + defaultPresets, + isDefaultPreset, + getFallbackPreset, +} from '/common/presets' import { store } from '../db' import { AppSchema } from '../../common/types/schema' import { AppLog, logger } from '../logger' @@ -68,6 +73,7 @@ type InferenceRequest = { service?: string log: AppLog retries?: number + maxTokens?: number } export async function inferenceAsync(opts: InferenceRequest) { @@ -138,7 +144,7 @@ export async function createInferenceStream(opts: InferenceRequest) { opts.settings = settings } - opts.settings.maxTokens = 1024 + opts.settings.maxTokens = opts.maxTokens ? opts.maxTokens : 1024 opts.settings.streamResponse = false opts.settings.temp = 0.5 @@ -171,7 +177,11 @@ export async function createInferenceStream(opts: InferenceRequest) { return { stream } } -export async function createTextStreamV2(opts: GenerateRequestV2, log: AppLog, guestSocketId?: string) { +export async function createTextStreamV2( + opts: GenerateRequestV2, + log: AppLog, + guestSocketId?: string +) { /** * N.b.: The front-end sends the `lines` and `history` in TIME-ASCENDING order. I.e. Oldest -> Newest * diff --git a/srv/adapter/goose.ts b/srv/adapter/goose.ts index 34f31e50c..8eb488266 100644 --- a/srv/adapter/goose.ts +++ b/srv/adapter/goose.ts @@ -57,7 +57,8 @@ export const handleGooseAI: ModelAdapter = async function* (opts) { if (resp.statusCode && resp.statusCode >= 400) { log.error({ body: resp.body }, `GooseAI request failed (${resp.statusCode})`) - const msg = resp.body?.error?.message || resp.body.message || resp.statusMessage || 'Unknown error' + const msg = + resp.body?.error?.message || resp.body.message || resp.statusMessage || 'Unknown error' yield { error: `GooseAI request failed (${resp.statusCode}): ${msg}`, @@ -73,7 +74,9 @@ export const handleGooseAI: ModelAdapter = async function* (opts) { return } const parsed = sanitise(text.replace(opts.prompt, '')) - const trimmed = trimResponseV2(parsed, opts.replyAs, opts.members, opts.characters, ['END_OF_DIALOG']) + const trimmed = trimResponseV2(parsed, opts.replyAs, opts.members, opts.characters, [ + 'END_OF_DIALOG', + ]) yield trimmed || parsed } catch (ex: any) { log.error({ err: ex }, 'GooseAI failed to parse') diff --git a/srv/adapter/horde.ts b/srv/adapter/horde.ts index 7b69f5769..ad380ee1a 100644 --- a/srv/adapter/horde.ts +++ b/srv/adapter/horde.ts @@ -17,7 +17,11 @@ export const handleHorde: ModelAdapter = async function* ({ ...opts }) { try { - const key = user.hordeKey ? (guest ? user.hordeKey : decryptText(user.hordeKey)) : HORDE_GUEST_KEY + const key = user.hordeKey + ? guest + ? user.hordeKey + : decryptText(user.hordeKey) + : HORDE_GUEST_KEY yield { prompt } @@ -47,7 +51,9 @@ export const handleHorde: ModelAdapter = async function* ({ yield trimmed || sanitised } catch (ex: any) { logger.error({ err: ex, body: ex.body }, `Horde request failed.`) - let msg = [ex?.body?.message || '', JSON.stringify(ex?.body?.errors) || ''].filter((line) => !!line) + let msg = [ex?.body?.message || '', JSON.stringify(ex?.body?.errors) || ''].filter( + (line) => !!line + ) yield { error: `${ex.message}. ${msg.join('. ')}` } } } diff --git a/srv/adapter/kobold.ts b/srv/adapter/kobold.ts index 715e828e9..3947cce82 100644 --- a/srv/adapter/kobold.ts +++ b/srv/adapter/kobold.ts @@ -94,7 +94,10 @@ export const handleKobold: ModelAdapter = async function* ({ } const parsed = sanitise(accum) - const trimmed = trimResponseV2(parsed, opts.replyAs, members, characters, ['END_OF_DIALOG', 'You:']) + const trimmed = trimResponseV2(parsed, opts.replyAs, members, characters, [ + 'END_OF_DIALOG', + 'You:', + ]) yield trimmed || parsed } diff --git a/srv/adapter/novel.ts b/srv/adapter/novel.ts index 438128065..a3c9272a2 100644 --- a/srv/adapter/novel.ts +++ b/srv/adapter/novel.ts @@ -70,7 +70,10 @@ export const handleNovel: ModelAdapter = async function* ({ const endTokens = ['***', 'Scenario:', '----', '⁂'] - log.debug({ ...body, input: null, parameters: { ...body.parameters, bad_words_ids: null } }, 'NovelAI payload') + log.debug( + { ...body, input: null, parameters: { ...body.parameters, bad_words_ids: null } }, + 'NovelAI payload' + ) log.debug(`Prompt:\n${body.input}`) const headers = { diff --git a/srv/adapter/ooba.ts b/srv/adapter/ooba.ts index 94b3897fd..9e09e394b 100644 --- a/srv/adapter/ooba.ts +++ b/srv/adapter/ooba.ts @@ -12,7 +12,15 @@ import { logger } from '../logger' const defaultUrl = `http://127.0.0.1:7860` -export const handleOoba: ModelAdapter = async function* ({ char, members, user, prompt, settings, log, ...opts }) { +export const handleOoba: ModelAdapter = async function* ({ + char, + members, + user, + prompt, + settings, + log, + ...opts +}) { const body = { prompt, max_new_tokens: settings.max_new_tokens, @@ -42,9 +50,14 @@ export const handleOoba: ModelAdapter = async function* ({ char, members, user, log.debug({ ...body, prompt: null }, 'Textgen payload') log.debug(`Prompt:\n${body.prompt}`) - const resp = await needle('post', `${normalizeUrl(user.oobaUrl, defaultUrl)}/api/v1/generate`, body, { - json: true, - }).catch((err) => ({ error: err })) + const resp = await needle( + 'post', + `${normalizeUrl(user.oobaUrl, defaultUrl)}/api/v1/generate`, + body, + { + json: true, + } + ).catch((err) => ({ error: err })) if ('error' in resp) { logger.error({ err: resp.error }, ``) @@ -71,7 +84,9 @@ export const handleOoba: ModelAdapter = async function* ({ char, members, user, return } const parsed = sanitise(text.replace(prompt, '')) - const trimmed = trimResponseV2(parsed, opts.replyAs, members, opts.characters, ['END_OF_DIALOG']) + const trimmed = trimResponseV2(parsed, opts.replyAs, members, opts.characters, [ + 'END_OF_DIALOG', + ]) yield trimmed || parsed } catch (ex: any) { yield { error: `Textgen request failed: ${ex.message}` } diff --git a/srv/adapter/openai.ts b/srv/adapter/openai.ts index 1d58e23c0..8c8f872e1 100644 --- a/srv/adapter/openai.ts +++ b/srv/adapter/openai.ts @@ -36,7 +36,10 @@ type CompletionGenerator = ( headers: Record, body: any, log: AppLog -) => AsyncGenerator<{ error: string } | { error?: undefined; token: string }, Completion | undefined> +) => AsyncGenerator< + { error: string } | { error?: undefined; token: string }, + Completion | undefined +> export const handleOAI: ModelAdapter = async function* (opts) { const { char, members, user, prompt, settings, log, guest, gen, kind, isThirdParty } = opts @@ -48,7 +51,8 @@ export const handleOAI: ModelAdapter = async function* (opts) { } const oaiModel = settings.oaiModel ?? defaultPresets.openai.oaiModel - const maxResponseLength = opts.chat.mode === 'adventure' ? 400 : gen.maxTokens ?? defaultPresets.openai.maxTokens + const maxResponseLength = + opts.chat.mode === 'adventure' ? 400 : gen.maxTokens ?? defaultPresets.openai.maxTokens const body: any = { model: oaiModel, @@ -78,7 +82,11 @@ export const handleOAI: ModelAdapter = async function* (opts) { if (gen.antiBond) body.logit_bias = { 3938: -50, 11049: -50, 64186: -50, 3717: -25 } const useThirdPartyPassword = base.changed && isThirdParty && user.thirdPartyPassword - const apiKey = useThirdPartyPassword ? user.thirdPartyPassword : !isThirdParty ? user.oaiKey : null + const apiKey = useThirdPartyPassword + ? user.thirdPartyPassword + : !isThirdParty + ? user.oaiKey + : null const bearer = !!guest ? `Bearer ${apiKey}` : apiKey ? `Bearer ${decryptText(apiKey)}` : null const headers: any = { @@ -172,9 +180,13 @@ export async function getOpenAIUsage(oaiKey: string, guest: boolean): Promise= 400) { throw new StatusError( `Failed to retrieve usage (${res.statusCode}): ${res.body?.message || res.statusMessage}`, @@ -185,7 +197,13 @@ export async function getOpenAIUsage(oaiKey: string, guest: boolean): Promise= 400) { - const msg = resp.body?.error?.message || resp.body.message || resp.statusMessage || 'Unknown error' + const msg = + resp.body?.error?.message || resp.body.message || resp.statusMessage || 'Unknown error' yield { error: `OpenAI request failed (${resp.statusCode}): ${msg}` } return diff --git a/srv/adapter/openrouter.ts b/srv/adapter/openrouter.ts index 9bf1dba17..d20aea2d0 100644 --- a/srv/adapter/openrouter.ts +++ b/srv/adapter/openrouter.ts @@ -104,7 +104,8 @@ async function* getCompletion(payload: any, headers: any): AsyncGenerator { } if (resp.statusCode && resp.statusCode >= 400) { - const msg = resp.body.message || resp.body.error?.message || resp.statusMessage || 'Unknown error' + const msg = + resp.body.message || resp.body.error?.message || resp.statusMessage || 'Unknown error' yield { error: `OpenRouter request failed (${resp.statusCode}): ${msg}` } return } diff --git a/srv/adapter/prompt.ts b/srv/adapter/prompt.ts index 7ef98492c..b3269b657 100644 --- a/srv/adapter/prompt.ts +++ b/srv/adapter/prompt.ts @@ -13,7 +13,10 @@ type PromptOpts = { const DEFAULT_MAX_TOKENS = 2048 -export async function getMessagesForPrompt({ chat, settings, char, members, retry }: PromptOpts, encoder: Encoder) { +export async function getMessagesForPrompt( + { chat, settings, char, members, retry }: PromptOpts, + encoder: Encoder +) { const maxContext = settings.maxContextLength || DEFAULT_MAX_TOKENS let before: string | undefined let tokens = 0 diff --git a/srv/adapter/register.ts b/srv/adapter/register.ts index 0dcba330e..a39adfc6a 100644 --- a/srv/adapter/register.ts +++ b/srv/adapter/register.ts @@ -11,7 +11,9 @@ const adapters = new Map<|assistant|>') - .replace(new RegExp(`^${opts.members[0].handle || 'You'}:`, 'gm'), '<|endoftext|><|prompter|>') + .replace( + new RegExp(`^${opts.members[0].handle || 'You'}:`, 'gm'), + '<|endoftext|><|prompter|>' + ) input = { prompt, max_length: encoder(opts.prompt) + (opts.gen.maxTokens || 500), @@ -248,7 +251,9 @@ export const handleReplicate: ModelAdapter = async function* (opts) { case 'failed': case 'canceled': default: - throw new Error(`Replicate prediction request status: ${status} (error: ${prediction.error})`) + throw new Error( + `Replicate prediction request status: ${status} (error: ${prediction.error})` + ) } } @@ -369,7 +374,10 @@ export async function getCollection(key: string, slug: string) { export async function getLanguageCollection(key: string): Promise> { const collection = await getCollection(key, COLLECTIONS.language) - const models = collection.models.reduce((prev: any, curr: any) => Object.assign(prev, { [curr.name]: curr }), {}) + const models = collection.models.reduce( + (prev: any, curr: any) => Object.assign(prev, { [curr.name]: curr }), + {} + ) return models } diff --git a/srv/adapter/scale.ts b/srv/adapter/scale.ts index 9daccffd7..2dd8e446d 100644 --- a/srv/adapter/scale.ts +++ b/srv/adapter/scale.ts @@ -3,7 +3,15 @@ import { decryptText } from '../db/util' import { sanitise, trimResponseV2 } from '../api/chat/common' import { ModelAdapter } from './type' -export const handleScale: ModelAdapter = async function* ({ char, members, user, prompt, guest, log, ...opts }) { +export const handleScale: ModelAdapter = async function* ({ + char, + members, + user, + prompt, + guest, + log, + ...opts +}) { if (!user.scaleApiKey) { yield { error: 'Scale API key not set' } return diff --git a/srv/adapter/stream.ts b/srv/adapter/stream.ts index 9afbfe4b5..7463c136d 100644 --- a/srv/adapter/stream.ts +++ b/srv/adapter/stream.ts @@ -17,7 +17,10 @@ export async function* needleToSSE(needleStream: NodeJS.ReadableStream) { if (statusCode > 201) { needleStream.emit('err', new Error(`SSE request failed with status code ${statusCode}`)) } else if (!headers['content-type']?.startsWith('text/event-stream')) { - needleStream.emit('err', new Error(`SSE request received unexpected content-type ${headers['content-type']}`)) + needleStream.emit( + 'err', + new Error(`SSE request received unexpected content-type ${headers['content-type']}`) + ) } }) diff --git a/srv/api/chat/common.ts b/srv/api/chat/common.ts index b0bbe7d60..5ecdfa11e 100644 --- a/srv/api/chat/common.ts +++ b/srv/api/chat/common.ts @@ -89,11 +89,17 @@ export function sanitiseAndTrim( members: AppSchema.Profile[] ) { const parsed = sanitise(text.replace(prompt, '')) - const trimmed = trimResponseV2(parsed, char, members, characters, ['END_OF_DIALOG']).split(`${char.name}:`).join('') + const trimmed = trimResponseV2(parsed, char, members, characters, ['END_OF_DIALOG']) + .split(`${char.name}:`) + .join('') return trimmed || parsed } -export function getEndTokens(char: AppSchema.Character | null, members: AppSchema.Profile[], endTokens: string[] = []) { +export function getEndTokens( + char: AppSchema.Character | null, + members: AppSchema.Profile[], + endTokens: string[] = [] +) { const baseEndTokens = ['END_OF_DIALOG', ''].concat(endTokens) if (customSettings.baseEndTokens) { diff --git a/srv/api/chat/guest-msg.ts b/srv/api/chat/guest-msg.ts index 89d9df094..75e184db1 100644 --- a/srv/api/chat/guest-msg.ts +++ b/srv/api/chat/guest-msg.ts @@ -1,5 +1,7 @@ import { handle } from '../wrap' export const guestGenerateMsg = handle(async ({ params, body, log, socketId }, res) => { - return res.status(400).json({ message: 'Your browser is running on an old version. Please refresh.' }) + return res + .status(400) + .json({ message: 'Your browser is running on an old version. Please refresh.' }) }) diff --git a/srv/api/chat/index.ts b/srv/api/chat/index.ts index 5744334c9..b33330943 100644 --- a/srv/api/chat/index.ts +++ b/srv/api/chat/index.ts @@ -1,7 +1,13 @@ import { Router } from 'express' import { loggedIn } from '../auth' import { createChat, importChat } from './create' -import { restartChat, updateChat, updateChatGenPreset, updateChatGenSettings, updateMessage } from './edit' +import { + restartChat, + updateChat, + updateChatGenPreset, + updateChatGenSettings, + updateMessage, +} from './edit' import { getAllChats, getCharacterChats, getChatDetail } from './get' import { guestGenerateMsg } from './guest-msg' import { createImage } from './image' diff --git a/srv/api/chat/inference.ts b/srv/api/chat/inference.ts index 4de5d176a..21099a5ab 100644 --- a/srv/api/chat/inference.ts +++ b/srv/api/chat/inference.ts @@ -8,7 +8,12 @@ import { AppSchema } from '/common/types' import { runGuidance } from '/common/guidance/guidance-parser' import { cyoaTemplate } from '/common/default-preset' -const validInference = { prompt: 'string', settings: 'any', user: 'any', service: 'string?' } as const +const validInference = { + prompt: 'string', + settings: 'any', + user: 'any', + service: 'string?', +} as const export const generateActions = wrap(async ({ userId, log, body, socketId, params }) => { body.prompt = '' @@ -58,7 +63,10 @@ export const generateActions = wrap(async ({ userId, log, body, socketId, params const { values } = await runGuidance(prompt, { infer, - placeholders: { history: body.lines.join('\n'), user: body.impersonating?.name || body.profile.handle }, + placeholders: { + history: body.lines.join('\n'), + user: body.impersonating?.name || body.profile.handle, + }, }) const actions: AppSchema.ChatAction[] = [] @@ -79,13 +87,14 @@ export const generateActions = wrap(async ({ userId, log, body, socketId, params }) export const guidance = wrap(async ({ userId, log, body, socketId }) => { - assertValid({ ...validInference, placeholders: 'any?' }, body) + assertValid({ ...validInference, placeholders: 'any?', maxTokens: 'number?' }, body) const settings = await assertSettings(body, userId) const infer = async (text: string) => { const inference = await inferenceAsync({ user: body.user, + maxTokens: body.maxTokens, settings, log, prompt: text, @@ -165,12 +174,19 @@ async function assertSettings(body: any, userId: string) { let settings = body.settings as Partial | null if (userId) { const id = body.settings._id as string - settings = !id ? body.settings : isDefaultPreset(id) ? defaultPresets[id] : await store.presets.getUserPreset(id) + settings = !id + ? body.settings + : isDefaultPreset(id) + ? defaultPresets[id] + : await store.presets.getUserPreset(id) body.user = await store.users.getUser(userId) } if (!settings) { - throw new StatusError('The preset used does not have a service configured. Configure it from the presets page', 400) + throw new StatusError( + 'The preset used does not have a service configured. Configure it from the presets page', + 400 + ) } if (!body.user) { diff --git a/srv/api/chat/message.ts b/srv/api/chat/message.ts index 838399bc9..4b49ea436 100644 --- a/srv/api/chat/message.ts +++ b/srv/api/chat/message.ts @@ -133,7 +133,10 @@ export const generateMessageV2 = handle(async (req, res) => { } // Coalesce for backwards compatibly while new UI rolls out - const replyAs = await store.characters.getCharacter(chat.userId, body.replyAs._id || body.char._id) + const replyAs = await store.characters.getCharacter( + chat.userId, + body.replyAs._id || body.char._id + ) if (chat.userId !== userId) { const isAllowed = await store.chats.canViewChat(userId, chat) @@ -302,7 +305,10 @@ export const generateMessageV2 = handle(async (req, res) => { const { values } = await runGuidance(prompt, { infer, - placeholders: { history: lines.join('\n'), user: body.impersonate?.name || body.sender.handle }, + placeholders: { + history: lines.join('\n'), + user: body.impersonate?.name || body.sender.handle, + }, }) actions.push({ emote: values.emote1, action: values.action1 }) actions.push({ emote: values.emote2, action: values.action2 }) @@ -448,7 +454,11 @@ async function handleGuestGenerate(body: GenRequest, req: AppRequest, res: Respo const requestId = v4() res.json({ success: true, generating: true, message: 'Generating message', requestId }) - const { stream, adapter } = await createTextStreamV2({ ...body, chat, replyAs, requestId }, log, guest) + const { stream, adapter } = await createTextStreamV2( + { ...body, chat, replyAs, requestId }, + log, + guest + ) log.setBindings({ adapter }) @@ -562,7 +572,10 @@ async function ensureBotMembership( if (impersonate && characters[impersonate._id] === undefined) { const actual = await store.characters.getCharacter(impersonate.userId, impersonate._id) if (!actual) { - throw new StatusError('Could not create message: Impersonation character does not belong to you', 403) + throw new StatusError( + 'Could not create message: Impersonation character does not belong to you', + 403 + ) } // Ensure the caller's character is up to date diff --git a/srv/api/request.ts b/srv/api/request.ts index 697ba9fad..29bfe3b2e 100644 --- a/srv/api/request.ts +++ b/srv/api/request.ts @@ -40,9 +40,11 @@ export async function get({ url, apikey, ...opts }: Omit ({ - error, - })) + const res = await needle('get', `${opts.host || baseUrl}${url}`, { json: true, headers }).catch( + (error) => ({ + error, + }) + ) if ('error' in res) { const error = new Error(`Could not reach server: ${res.error.message}`) diff --git a/srv/api/settings.ts b/srv/api/settings.ts index db69e5e99..999b6c51d 100644 --- a/srv/api/settings.ts +++ b/srv/api/settings.ts @@ -32,7 +32,9 @@ export async function getAppConfig() { selfhosting: config.jsonStorage, canAuth: false, imagesSaved: config.storage.saveImages, - assetPrefix: config.storage.enabled ? `https://${config.storage.bucket}.${config.storage.endpoint}` : '', + assetPrefix: config.storage.enabled + ? `https://${config.storage.bucket}.${config.storage.endpoint}` + : '', registered: getRegisteredAdapters().map(toRegisteredAdapter), maintenance: config.ui.maintenance, patreon: config.ui.patreon, diff --git a/srv/api/upload.ts b/srv/api/upload.ts index 760734d74..0cf0616cc 100644 --- a/srv/api/upload.ts +++ b/srv/api/upload.ts @@ -25,7 +25,10 @@ export type Attachment = { ext: string } -export function handleForm(req: Request, type: T): UnwrapBody & { attachments: Attachment[] } { +export function handleForm( + req: Request, + type: T +): UnwrapBody & { attachments: Attachment[] } { const attachments: Attachment[] = [] if (Array.isArray(req.files)) { diff --git a/srv/api/user/services.ts b/srv/api/user/services.ts index 008b74676..b4110e4f9 100644 --- a/srv/api/user/services.ts +++ b/srv/api/user/services.ts @@ -28,14 +28,17 @@ export const novelLogin = handle(async ({ userId, body }) => { ) if (res.statusCode && res.statusCode >= 400) { - throw new StatusError(`Failed to authenticate with NovelAI: ${res.statusMessage}`, res.statusCode) + throw new StatusError( + `Failed to authenticate with NovelAI: ${res.statusMessage}`, + res.statusCode + ) } await verifyNovelKey(res.body.accessToken) if (userId) { await store.users.updateUser(userId, { - novelApiKey: res.body.accessToken, + novelApiKey: encryptText(res.body.accessToken), novelVerified: true, }) } diff --git a/srv/api/user/settings.ts b/srv/api/user/settings.ts index 8a1be2a55..8260263e1 100644 --- a/srv/api/user/settings.ts +++ b/srv/api/user/settings.ts @@ -217,7 +217,8 @@ export const updateConfig = handle(async ({ userId, body }) => { const prevKey = prevUser.hordeKey const incomingKey = body.hordeKey || body.hordeApiKey! - const isNewKey = body.hordeKey !== '' && body.hordeKey !== HORDE_GUEST_KEY && body.hordeKey !== prevKey + const isNewKey = + body.hordeKey !== '' && body.hordeKey !== HORDE_GUEST_KEY && body.hordeKey !== prevKey if (isNewKey) { const user = await verifyHordeKey(incomingKey) @@ -228,7 +229,9 @@ export const updateConfig = handle(async ({ userId, body }) => { } const validatedThirdPartyUrl = - body.thirdPartyFormat === 'kobold' ? await verifyKobldUrl(prevUser, body.koboldUrl) : body.koboldUrl + body.thirdPartyFormat === 'kobold' + ? await verifyKobldUrl(prevUser, body.koboldUrl) + : body.koboldUrl if (validatedThirdPartyUrl) { update.koboldUrl = validatedThirdPartyUrl @@ -405,49 +408,53 @@ async function verifyHordeKey(key: string) { export async function getSafeUserConfig(userId: string) { const user = await store.users.getUser(userId!) - if (user) { - if (user.novelApiKey) { - user.novelApiKey = '' + if (!user) return + + if (user.novelApiKey) { + if (user.novelApiKey.includes('|') === false) { + await store.users.updateUser(userId, { novelApiKey: encryptText(user.novelApiKey) }) } - user.hordeKey = '' + user.novelApiKey = '' + } - if (user.oaiKey) { - user.oaiKeySet = true - user.oaiKey = '' - } + user.hordeKey = '' - if (user.scaleApiKey) { - user.scaleApiKeySet = true - user.scaleApiKey = '' - } + if (user.oaiKey) { + user.oaiKeySet = true + user.oaiKey = '' + } - if (user.claudeApiKey) { - user.claudeApiKey = '' - user.claudeApiKeySet = true - } + if (user.scaleApiKey) { + user.scaleApiKeySet = true + user.scaleApiKey = '' + } - if (user.thirdPartyPassword) { - user.thirdPartyPassword = '' - user.thirdPartyPasswordSet = true - } + if (user.claudeApiKey) { + user.claudeApiKey = '' + user.claudeApiKeySet = true + } - if (user.elevenLabsApiKey) { - user.elevenLabsApiKey = '' - user.elevenLabsApiKeySet = true - } + if (user.thirdPartyPassword) { + user.thirdPartyPassword = '' + user.thirdPartyPasswordSet = true + } + + if (user.elevenLabsApiKey) { + user.elevenLabsApiKey = '' + user.elevenLabsApiKeySet = true + } - for (const svc of getRegisteredAdapters()) { - if (!user.adapterConfig) break - if (!user.adapterConfig[svc.name]) continue + for (const svc of getRegisteredAdapters()) { + if (!user.adapterConfig) break + if (!user.adapterConfig[svc.name]) continue - const secrets = svc.settings.filter((opt) => opt.secret) + const secrets = svc.settings.filter((opt) => opt.secret) - for (const secret of secrets) { - if (user.adapterConfig[svc.name]![secret.field]) { - user.adapterConfig[svc.name]![secret.field] = '' - user.adapterConfig[svc.name]![secret.field + 'Set'] = true - } + for (const secret of secrets) { + if (user.adapterConfig[svc.name]![secret.field]) { + user.adapterConfig[svc.name]![secret.field] = '' + user.adapterConfig[svc.name]![secret.field + 'Set'] = true } } } diff --git a/srv/api/ws/bus.ts b/srv/api/ws/bus.ts index cebfee8b8..7d5c8be27 100644 --- a/srv/api/ws/bus.ts +++ b/srv/api/ws/bus.ts @@ -73,7 +73,10 @@ export async function initMessageBus() { setInterval(() => { const count = getAllCount() - clients.pub.publish(COUNT_EVENT, JSON.stringify({ count, hostname: `${os.hostname()}-${process.pid}` })) + clients.pub.publish( + COUNT_EVENT, + JSON.stringify({ count, hostname: `${os.hostname()}-${process.pid}` }) + ) }, 2000) clients.sub.subscribe(COUNT_EVENT, (msg) => { diff --git a/srv/bin.ts b/srv/bin.ts index 9cebecb4c..a5852f265 100644 --- a/srv/bin.ts +++ b/srv/bin.ts @@ -32,8 +32,16 @@ if (debug) { process.env.LOG_LEVEL = 'debug' } -const jsonLocation = flag(`Provide a location for the JSON files folder. Defaults to: ${folders.json}`, 'f', 'files') -const assets = flag(`Provide a location for the assets (images) folder. Defaults to: ${folders.assets}`, 'a', 'assets') +const jsonLocation = flag( + `Provide a location for the JSON files folder. Defaults to: ${folders.json}`, + 'f', + 'files' +) +const assets = flag( + `Provide a location for the assets (images) folder. Defaults to: ${folders.assets}`, + 'a', + 'assets' +) if (jsonLocation) { if (typeof jsonLocation !== 'string') { diff --git a/srv/config.ts b/srv/config.ts index a9750766f..a3f861b3d 100644 --- a/srv/config.ts +++ b/srv/config.ts @@ -33,10 +33,14 @@ if (!process.env.JWT_SECRET) { if (secret) { process.env.JWT_SECRET = secret } else if (!secret && process.env.NODE_ENV === 'production') { - throw new Error(`JWT_SECRET not set and .token_secret file does not exist. One must be provided in production.`) + throw new Error( + `JWT_SECRET not set and .token_secret file does not exist. One must be provided in production.` + ) } else { const newSecret = v4() - const secretPath = process.env.JSON_FOLDER ? resolve(process.env.JSON_FOLDER, '.token_secret') : '.token_secret' + const secretPath = process.env.JSON_FOLDER + ? resolve(process.env.JSON_FOLDER, '.token_secret') + : '.token_secret' writeFileSync(secretPath, newSecret) process.env.JWT_SECRET = newSecret } @@ -82,7 +86,10 @@ export const config = { username: env('INITIAL_USER', 'admin'), password: env('INITIAL_PASSWORD', v4()), }, - adapters: env('ADAPTERS', 'novel,horde,kobold,openai,openrouter,scale,claude,ooba,goose,replicate') + adapters: env( + 'ADAPTERS', + 'novel,horde,kobold,openai,openrouter,scale,claude,ooba,goose,replicate' + ) .split(',') .filter((i) => !!i && i in ADAPTER_LABELS) as AIAdapter[], storage: { diff --git a/srv/db/characters.ts b/srv/db/characters.ts index e676a6d23..24fb7ea7a 100644 --- a/srv/db/characters.ts +++ b/srv/db/characters.ts @@ -79,7 +79,10 @@ export async function updateCharacter(id: string, userId: string, char: Characte return getCharacter(userId, id) } -export async function getCharacter(userId: string, id: string): Promise { +export async function getCharacter( + userId: string, + id: string +): Promise { const char = await db('character').findOne({ _id: id, userId }) return char || undefined } diff --git a/srv/db/chats.ts b/srv/db/chats.ts index 4dcc55ad3..a40e84662 100644 --- a/srv/db/chats.ts +++ b/srv/db/chats.ts @@ -45,7 +45,15 @@ export async function create( characterId: string, props: Pick< AppSchema.Chat, - 'name' | 'greeting' | 'scenario' | 'scenarioIds' | 'sampleChat' | 'userId' | 'overrides' | 'genPreset' | 'mode' + | 'name' + | 'greeting' + | 'scenario' + | 'scenarioIds' + | 'sampleChat' + | 'userId' + | 'overrides' + | 'genPreset' + | 'mode' > ) { const id = `${v4()}` @@ -174,7 +182,10 @@ export async function getActiveMembers(chatId: string) { } export async function setChatCharacter(chatId: string, charId: string, state: boolean) { - await db('chat').updateOne({ _id: chatId }, { $set: { updatedAt: now(), [`characters.${charId}`]: state } }) + await db('chat').updateOne( + { _id: chatId }, + { $set: { updatedAt: now(), [`characters.${charId}`]: state } } + ) } export async function restartChat(userId: string, chatId: string) { diff --git a/srv/db/invite.ts b/srv/db/invite.ts index 3cb24bfa5..b7389f454 100644 --- a/srv/db/invite.ts +++ b/srv/db/invite.ts @@ -125,7 +125,10 @@ export async function answer(userId: string, inviteId: string, accept: boolean) if (accept) { await db('chat-member').insertOne(member) - await db('chat').updateOne({ _id: chat._id, kind: 'chat' }, { $set: { memberIds: chat.memberIds.concat(userId) } }) + await db('chat').updateOne( + { _id: chat._id, kind: 'chat' }, + { $set: { memberIds: chat.memberIds.concat(userId) } } + ) const profile = await db('profile').findOne({ userId }) sendMany([chat.userId, ...chat.memberIds.concat(userId)], { type: 'member-added', diff --git a/srv/db/messages.ts b/srv/db/messages.ts index 3a4d125bf..20f96df33 100644 --- a/srv/db/messages.ts +++ b/srv/db/messages.ts @@ -23,7 +23,18 @@ export type NewMessage = { export type ImportedMessage = NewMessage & { createdAt: string } export async function createChatMessage(creating: NewMessage, ephemeral?: boolean) { - const { chatId, message, characterId, senderId, adapter, ooc, imagePrompt, actions, meta, event } = creating + const { + chatId, + message, + characterId, + senderId, + adapter, + ooc, + imagePrompt, + actions, + meta, + event, + } = creating const doc: AppSchema.ChatMessage = { _id: creating._id || v4(), kind: 'chat-message', diff --git a/srv/db/oauth.ts b/srv/db/oauth.ts index 6fa2d7d11..9e1611272 100644 --- a/srv/db/oauth.ts +++ b/srv/db/oauth.ts @@ -69,7 +69,8 @@ export async function verifyApiKey(apikey: string) { if (!key) throw errors.Unauthorized - if (key) return { scopes: key.scopes, userId: key.userId, username: key.username, admin: !!key.admin } + if (key) + return { scopes: key.scopes, userId: key.userId, username: key.username, admin: !!key.admin } } export async function getSafeUserKeys(userId: string) { diff --git a/srv/db/presets.ts b/srv/db/presets.ts index b5eb9c908..08d0e6e58 100644 --- a/srv/db/presets.ts +++ b/srv/db/presets.ts @@ -7,7 +7,10 @@ export async function updateGenSetting(chatId: string, props: AppSchema.Chat['ge } export async function updateGenPreset(chatId: string, preset: string) { - await db('chat').updateOne({ _id: chatId }, { $set: { genSettings: null as any, genPreset: preset } }) + await db('chat').updateOne( + { _id: chatId }, + { $set: { genSettings: null as any, genPreset: preset } } + ) } export async function createUserPreset(userId: string, settings: AppSchema.GenSettings) { @@ -32,7 +35,11 @@ export async function getUserPresets(userId: string) { return presets } -export async function updateUserPreset(userId: string, presetId: string, update: AppSchema.GenSettings) { +export async function updateUserPreset( + userId: string, + presetId: string, + update: AppSchema.GenSettings +) { await db('gen-setting').updateOne({ _id: presetId, userId }, { $set: update }) const updated = await db('gen-setting').findOne({ _id: presetId }) return updated diff --git a/srv/image/horde.ts b/srv/image/horde.ts index 9526c485b..67933491c 100644 --- a/srv/image/horde.ts +++ b/srv/image/horde.ts @@ -4,7 +4,11 @@ import { decryptText } from '../db/util' import { HORDE_GUEST_KEY } from '../api/horde' export const handleHordeImage: ImageAdapter = async ({ user, prompt }, log, guestId) => { - const key = user.hordeKey ? (guestId ? user.hordeKey : decryptText(user.hordeKey)) : HORDE_GUEST_KEY + const key = user.hordeKey + ? guestId + ? user.hordeKey + : decryptText(user.hordeKey) + : HORDE_GUEST_KEY const { text: image } = await horde.generateImage({ ...user, hordeKey: key }, prompt, log) const buffer = Buffer.from(image, 'base64') diff --git a/srv/image/novel.ts b/srv/image/novel.ts index 347b641a4..34a042e6c 100644 --- a/srv/image/novel.ts +++ b/srv/image/novel.ts @@ -80,7 +80,11 @@ export const handleNovelImage: ImageAdapter = async ({ user, prompt }, log, gues }) if (result.statusCode && result.statusCode >= 400) { - throw new Error(`Failed to generate image: ${result.body.message || result.statusMessage} (${result.statusCode})`) + throw new Error( + `Failed to generate image: ${result.body.message || result.statusMessage} (${ + result.statusCode + })` + ) } const zip = new Zip(result.body).getEntries() diff --git a/srv/image/stable-diffusion.ts b/srv/image/stable-diffusion.ts index 0d92d9f57..5585d4919 100644 --- a/srv/image/stable-diffusion.ts +++ b/srv/image/stable-diffusion.ts @@ -64,7 +64,11 @@ export const handleSDImage: ImageAdapter = async ({ user, prompt }, log, guestId }) if (result.statusCode && result.statusCode >= 400) { - throw new Error(`Failed to generate image: ${result.body.message || result.statusMessage} (${result.statusCode})`) + throw new Error( + `Failed to generate image: ${result.body.message || result.statusMessage} (${ + result.statusCode + })` + ) } const image = result.body.images[0] diff --git a/srv/start.ts b/srv/start.ts index e172148fb..14cff2c7d 100644 --- a/srv/start.ts +++ b/srv/start.ts @@ -23,7 +23,10 @@ export async function start() { await Promise.allSettled([initDb(), initMessageBus()]) server.listen(config.port, '0.0.0.0', async () => { - logger.info({ port: config.port, version: pkg.version }, `Server started http://127.0.0.1:${config.port}`) + logger.info( + { port: config.port, version: pkg.version }, + `Server started http://127.0.0.1:${config.port}` + ) if (config.publicTunnel) { await startTunnel() diff --git a/srv/voice/elevenlabs.ts b/srv/voice/elevenlabs.ts index 3642ad067..298775286 100644 --- a/srv/voice/elevenlabs.ts +++ b/srv/voice/elevenlabs.ts @@ -57,7 +57,11 @@ const handleElevenLabsVoicesList = async ( ) } -const handleElevenLabsTextToSpeech: TextToSpeechAdapter = async ({ user, text, voice }, log, guestId) => { +const handleElevenLabsTextToSpeech: TextToSpeechAdapter = async ( + { user, text, voice }, + log, + guestId +) => { const key = getKey(user, guestId) if (voice.service !== 'elevenlabs') throw new Error('Invalid service') const payload: ElevenLabsTextToSpeechRequest = { @@ -68,13 +72,18 @@ const handleElevenLabsTextToSpeech: TextToSpeechAdapter = async ({ user, text, v similarity_boost: voice.similarityBoost || 0.75, }, } - const result = await needle('post', `${baseUrl}/text-to-speech/${voice.voiceId}/stream`, payload, { - json: true, - headers: { - 'xi-api-key': key, - accept: 'audio/mpeg', - }, - }) + const result = await needle( + 'post', + `${baseUrl}/text-to-speech/${voice.voiceId}/stream`, + payload, + { + json: true, + headers: { + 'xi-api-key': key, + accept: 'audio/mpeg', + }, + } + ) if (result.statusCode !== 200) { throw new Error( diff --git a/srv/voice/index.ts b/srv/voice/index.ts index 658cee194..1d85fb4a6 100644 --- a/srv/voice/index.ts +++ b/srv/voice/index.ts @@ -105,7 +105,9 @@ export async function generateVoice( } if (!audio) { - error = `Failed to generate audio: ${error || 'Invalid text to speech settings (No handler found)'}` + error = `Failed to generate audio: ${ + error || 'Invalid text to speech settings (No handler found)' + }` send(broadcastIds, guestId, { type: 'voice-failed', chatId, diff --git a/srv/voice/novel.ts b/srv/voice/novel.ts index 4b37e0bcf..5a9d8d848 100644 --- a/srv/voice/novel.ts +++ b/srv/voice/novel.ts @@ -38,7 +38,11 @@ const handleNovelVoicesList = async ( })) } -const handleNovelTextToSpeech: TextToSpeechAdapter = async ({ user, text, voice }, log, guestId) => { +const handleNovelTextToSpeech: TextToSpeechAdapter = async ( + { user, text, voice }, + log, + guestId +) => { if (voice.service !== 'novel') throw new Error('Invalid service') const token = getToken(user, guestId) //https://api.novelai.net/ai/generate-voice?text=This%20is%20a%20test%20for%20text%20to%20speech.%20A%20little%20harsh%2C%20a%20little%20slow%2C%20but%20always%20on%20point.&voice=-1&seed=Aini&opus=true&version=v2 diff --git a/srv/voice/types.ts b/srv/voice/types.ts index aec6b4f25..b150deb73 100644 --- a/srv/voice/types.ts +++ b/srv/voice/types.ts @@ -5,7 +5,10 @@ import { AppLog } from '../logger' export type TextToSpeechHandler = { validator: Validator - getVoices: (user: AppSchema.User, guestId: string | undefined) => Promise + getVoices: ( + user: AppSchema.User, + guestId: string | undefined + ) => Promise generateVoice: TextToSpeechAdapter } diff --git a/web/App.tsx b/web/App.tsx index b7dd65ba9..cc3004248 100644 --- a/web/App.tsx +++ b/web/App.tsx @@ -49,7 +49,10 @@ const App: Component = () => { - } /> + } + /> @@ -58,12 +61,21 @@ const App: Component = () => { import('./pages/GenerationPresets'))} /> - import('./pages/GenerationPresets/PresetList'))} /> + import('./pages/GenerationPresets/PresetList'))} + /> import('./pages/Memory'))} /> - import('./pages/Memory/EditMemoryPage'))} /> - import('./pages/TermsOfService'))} /> + import('./pages/Memory/EditMemoryPage'))} + /> + import('./pages/TermsOfService'))} + /> import('./pages/PrivacyPolicy'))} /> @@ -73,8 +85,14 @@ const App: Component = () => { import('./pages/Invite/InvitesPage'))} /> - import('./pages/Admin/Metrics'))} /> - import('./pages/Admin/UsersPage'))} /> + import('./pages/Admin/Metrics'))} + /> + import('./pages/Admin/UsersPage'))} + /> @@ -119,7 +137,8 @@ const Layout: Component = () => { const bg = createMemo(() => { const styles: JSX.CSSProperties = { - 'background-image': state.background && !cfg.anonymize ? `url(${state.background})` : undefined, + 'background-image': + state.background && !cfg.anonymize ? `url(${state.background})` : undefined, 'background-repeat': 'no-repeat', 'background-size': 'cover', 'background-position': 'center', @@ -161,7 +180,10 @@ const Layout: Component = () => { - settingStore.toggleImpersonate(false)} /> + settingStore.toggleImpersonate(false)} + /> @@ -175,7 +197,12 @@ const InfoModal: Component = (props) => { const state = rootModalStore() return ( - rootModalStore.info()} maxWidth="half"> + rootModalStore.info()} + maxWidth="half" + > {state.info} ) diff --git a/web/Navigation.tsx b/web/Navigation.tsx index c2b57d67f..4ceed10b8 100644 --- a/web/Navigation.tsx +++ b/web/Navigation.tsx @@ -20,9 +20,26 @@ import { VenetianMask, X, } from 'lucide-solid' -import { Component, createEffect, createMemo, createSignal, JSX, Match, onMount, Show, Switch } from 'solid-js' +import { + Component, + createEffect, + createMemo, + createSignal, + JSX, + Match, + onMount, + Show, + Switch, +} from 'solid-js' import AvatarIcon, { CharacterAvatar } from './shared/AvatarIcon' -import { characterStore, chatStore, inviteStore, settingStore, toastStore, userStore } from './store' +import { + characterStore, + chatStore, + inviteStore, + settingStore, + toastStore, + userStore, +} from './store' import Slot from './shared/Slot' import { useEffect, useResizeObserver } from './shared/hooks' import WizardIcon from './icons/WizardIcon' @@ -75,7 +92,10 @@ const Navigation: Component = () => { return ( <> -
+
{({ time, toast, seen }) => ( - +

{time.toLocaleString()}

diff --git a/web/dots.css b/web/dots.css index 95fe08027..6c186f871 100644 --- a/web/dots.css +++ b/web/dots.css @@ -356,19 +356,23 @@ border-radius: 5px; background-color: var(--dot-color); color: var(--dot-color); - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); animation: dot-carousel 1.5s infinite linear; } @keyframes dot-carousel { 0% { - box-shadow: 9984px 0 0 -1px var(--dot-color), 9999px 0 0 1px var(--dot-color), 10014px 0 0 -1px var(--dot-color); + box-shadow: 9984px 0 0 -1px var(--dot-color), 9999px 0 0 1px var(--dot-color), + 10014px 0 0 -1px var(--dot-color); } 50% { - box-shadow: 10014px 0 0 -1px var(--dot-color), 9984px 0 0 -1px var(--dot-color), 9999px 0 0 1px var(--dot-color); + box-shadow: 10014px 0 0 -1px var(--dot-color), 9984px 0 0 -1px var(--dot-color), + 9999px 0 0 1px var(--dot-color); } 100% { - box-shadow: 9999px 0 0 1px var(--dot-color), 10014px 0 0 -1px var(--dot-color), 9984px 0 0 -1px var(--dot-color); + box-shadow: 9999px 0 0 1px var(--dot-color), 10014px 0 0 -1px var(--dot-color), + 9984px 0 0 -1px var(--dot-color); } } /** @@ -384,31 +388,39 @@ border-radius: 5px; background-color: var(--dot-color); color: var(--dot-color); - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); animation: dot-typing 1.5s infinite linear; } @keyframes dot-typing { 0% { - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); } 16.667% { - box-shadow: 9984px -10px 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px -10px 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); } 33.333% { - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); } 50% { - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px -10px 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px -10px 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); } 66.667% { - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); } 83.333% { - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px -10px 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px -10px 0 0 var(--dot-color); } 100% { - box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), 10014px 0 0 0 var(--dot-color); + box-shadow: 9984px 0 0 0 var(--dot-color), 9999px 0 0 0 var(--dot-color), + 10014px 0 0 0 var(--dot-color); } } /** @@ -474,49 +486,63 @@ border-radius: 5px; background-color: var(--dot-color); color: var(--dot-color); - box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color); + box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), + 10007px 0 0 0 var(--dot-color); animation: dot-bricks 2s infinite ease; } @keyframes dot-bricks { 0% { - box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color); + box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), + 10007px 0 0 0 var(--dot-color); } 8.333% { - box-shadow: 10007px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color); + box-shadow: 10007px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), + 10007px 0 0 0 var(--dot-color); } 16.667% { - box-shadow: 10007px -16px 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color); + box-shadow: 10007px -16px 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color), + 10007px 0 0 0 var(--dot-color); } 25% { - box-shadow: 10007px -16px 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color); + box-shadow: 10007px -16px 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color), + 9991px 0 0 0 var(--dot-color); } 33.333% { - box-shadow: 10007px 0 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color); + box-shadow: 10007px 0 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color), + 9991px 0 0 0 var(--dot-color); } 41.667% { - box-shadow: 10007px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color); + box-shadow: 10007px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color), + 9991px 0 0 0 var(--dot-color); } 50% { - box-shadow: 10007px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color); + box-shadow: 10007px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color), + 9991px -16px 0 0 var(--dot-color); } 58.333% { - box-shadow: 9991px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color); + box-shadow: 9991px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color), + 9991px -16px 0 0 var(--dot-color); } 66.666% { - box-shadow: 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color), 9991px -16px 0 0 var(--dot-color); + box-shadow: 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color), + 9991px -16px 0 0 var(--dot-color); } 75% { - box-shadow: 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color); + box-shadow: 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color), + 10007px -16px 0 0 var(--dot-color); } 83.333% { - box-shadow: 9991px -16px 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color); + box-shadow: 9991px -16px 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color), + 10007px -16px 0 0 var(--dot-color); } 91.667% { - box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), 10007px -16px 0 0 var(--dot-color); + box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), + 10007px -16px 0 0 var(--dot-color); } 100% { - box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), 10007px 0 0 0 var(--dot-color); + box-shadow: 9991px -16px 0 0 var(--dot-color), 9991px 0 0 0 var(--dot-color), + 10007px 0 0 0 var(--dot-color); } } /** @@ -661,49 +687,53 @@ border-radius: 5px; background-color: transparent; color: transparent; - box-shadow: 0 -18px 0 0 var(--dot-color), 12.727926px -12.727926px 0 0 var(--dot-color), 18px 0 0 0 var(--dot-color), - 12.727926px 12.727926px 0 0 rgba(152, 128, 255, 0), 0 18px 0 0 rgba(152, 128, 255, 0), - -12.727926px 12.727926px 0 0 rgba(152, 128, 255, 0), -18px 0 0 0 rgba(152, 128, 255, 0), - -12.727926px -12.727926px 0 0 rgba(152, 128, 255, 0); + box-shadow: 0 -18px 0 0 var(--dot-color), 12.727926px -12.727926px 0 0 var(--dot-color), + 18px 0 0 0 var(--dot-color), 12.727926px 12.727926px 0 0 rgba(152, 128, 255, 0), + 0 18px 0 0 rgba(152, 128, 255, 0), -12.727926px 12.727926px 0 0 rgba(152, 128, 255, 0), + -18px 0 0 0 rgba(152, 128, 255, 0), -12.727926px -12.727926px 0 0 rgba(152, 128, 255, 0); animation: dot-spin 1.5s infinite linear; } @keyframes dot-spin { 0%, 100% { - box-shadow: 0 -18px 0 0 var(--dot-color), 12.727926px -12.727926px 0 0 var(--dot-color), 18px 0 0 0 var(--dot-color), - 12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), 0 18px 0 -5px rgba(152, 128, 255, 0), - -12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), -18px 0 0 -5px rgba(152, 128, 255, 0), - -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); + box-shadow: 0 -18px 0 0 var(--dot-color), 12.727926px -12.727926px 0 0 var(--dot-color), + 18px 0 0 0 var(--dot-color), 12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), + 0 18px 0 -5px rgba(152, 128, 255, 0), -12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), + -18px 0 0 -5px rgba(152, 128, 255, 0), -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); } 12.5% { box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), 12.727926px -12.727926px 0 0 var(--dot-color), - 18px 0 0 0 var(--dot-color), 12.727926px 12.727926px 0 0 var(--dot-color), 0 18px 0 -5px rgba(152, 128, 255, 0), - -12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), -18px 0 0 -5px rgba(152, 128, 255, 0), - -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); + 18px 0 0 0 var(--dot-color), 12.727926px 12.727926px 0 0 var(--dot-color), + 0 18px 0 -5px rgba(152, 128, 255, 0), -12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), + -18px 0 0 -5px rgba(152, 128, 255, 0), -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); } 25% { - box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), - 18px 0 0 0 var(--dot-color), 12.727926px 12.727926px 0 0 var(--dot-color), 0 18px 0 0 var(--dot-color), + box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), + 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), 18px 0 0 0 var(--dot-color), + 12.727926px 12.727926px 0 0 var(--dot-color), 0 18px 0 0 var(--dot-color), -12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), -18px 0 0 -5px rgba(152, 128, 255, 0), -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); } 37.5% { - box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), - 18px 0 0 -5px rgba(152, 128, 255, 0), 12.727926px 12.727926px 0 0 var(--dot-color), 0 18px 0 0 var(--dot-color), + box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), + 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), 18px 0 0 -5px rgba(152, 128, 255, 0), + 12.727926px 12.727926px 0 0 var(--dot-color), 0 18px 0 0 var(--dot-color), -12.727926px 12.727926px 0 0 var(--dot-color), -18px 0 0 -5px rgba(152, 128, 255, 0), -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); } 50% { - box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), - 18px 0 0 -5px rgba(152, 128, 255, 0), 12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), - 0 18px 0 0 var(--dot-color), -12.727926px 12.727926px 0 0 var(--dot-color), -18px 0 0 0 var(--dot-color), + box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), + 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), 18px 0 0 -5px rgba(152, 128, 255, 0), + 12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), 0 18px 0 0 var(--dot-color), + -12.727926px 12.727926px 0 0 var(--dot-color), -18px 0 0 0 var(--dot-color), -12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0); } 62.5% { - box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), - 18px 0 0 -5px rgba(152, 128, 255, 0), 12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), - 0 18px 0 -5px rgba(152, 128, 255, 0), -12.727926px 12.727926px 0 0 var(--dot-color), -18px 0 0 0 var(--dot-color), + box-shadow: 0 -18px 0 -5px rgba(152, 128, 255, 0), + 12.727926px -12.727926px 0 -5px rgba(152, 128, 255, 0), 18px 0 0 -5px rgba(152, 128, 255, 0), + 12.727926px 12.727926px 0 -5px rgba(152, 128, 255, 0), 0 18px 0 -5px rgba(152, 128, 255, 0), + -12.727926px 12.727926px 0 0 var(--dot-color), -18px 0 0 0 var(--dot-color), -12.727926px -12.727926px 0 0 var(--dot-color); } 75% { diff --git a/web/pages/Admin/Metrics.tsx b/web/pages/Admin/Metrics.tsx index 8ecee866c..d4a2a6cf6 100644 --- a/web/pages/Admin/Metrics.tsx +++ b/web/pages/Admin/Metrics.tsx @@ -24,11 +24,23 @@ const MetricsPage: Component = () => {
- + - + - +
diff --git a/web/pages/Admin/UsersPage.tsx b/web/pages/Admin/UsersPage.tsx index 68d4a3cc1..12693f63c 100644 --- a/web/pages/Admin/UsersPage.tsx +++ b/web/pages/Admin/UsersPage.tsx @@ -58,7 +58,12 @@ const UsersPage: Component = () => { )} setPw(undefined)} /> - setInfo()} userId={info()?.id!} name={info()?.name!} /> + setInfo()} + userId={info()?.id!} + name={info()?.name!} + />
) @@ -66,7 +71,9 @@ const UsersPage: Component = () => { export default UsersPage -const InfoModel: Component<{ show: boolean; close: () => void; userId: string; name: string }> = (props) => { +const InfoModel: Component<{ show: boolean; close: () => void; userId: string; name: string }> = ( + props +) => { const state = adminStore() return ( @@ -80,7 +87,12 @@ const InfoModel: Component<{ show: boolean; close: () => void; userId: string; n - +
@@ -91,7 +103,9 @@ const InfoModel: Component<{ show: boolean; close: () => void; userId: string; n ) } -const PasswordModal: Component<{ user: AppSchema.User; show: boolean; close: () => void }> = (props) => { +const PasswordModal: Component<{ user: AppSchema.User; show: boolean; close: () => void }> = ( + props +) => { let ref: any const save = () => { const body = getStrictForm(ref, { newPassword: 'string' }) diff --git a/web/pages/Character/CharacterList.tsx b/web/pages/Character/CharacterList.tsx index 428f953bb..e58c2663e 100644 --- a/web/pages/Character/CharacterList.tsx +++ b/web/pages/Character/CharacterList.tsx @@ -1,4 +1,14 @@ -import { Component, For, Match, Show, Switch, createEffect, createMemo, createSignal, onMount } from 'solid-js' +import { + Component, + For, + Match, + Show, + Switch, + createEffect, + createMemo, + createSignal, + onMount, +} from 'solid-js' import { NewCharacter, characterStore } from '../../store' import { tagStore } from '../../store' import PageHeader from '../../shared/PageHeader' @@ -311,7 +321,11 @@ const Characters: Component<{ setDownload()} char={download()!} /> - setDelete(undefined)} /> + setDelete(undefined)} + /> ) } @@ -394,7 +408,11 @@ const Character: Component<{ -
-
{props.char.name}
+
+ {props.char.name} +
{/* hacky positioning shenanigans are necessary as opposed to using an absolute positioning because if any of the DropMenu parent is positioned, then DropMenu breaks because it relies on the nearest positioned parent to be the sitewide container */} -
setOpts(true)}> +
setOpts(true)} + >
- setOpts(false)} customPosition="right-[9px] top-[6px]"> + setOpts(false)} + customPosition="right-[9px] top-[6px]" + >
- - +
diff --git a/web/pages/Settings/UISettings.tsx b/web/pages/Settings/UISettings.tsx index 8f0387ab8..167d3250e 100644 --- a/web/pages/Settings/UISettings.tsx +++ b/web/pages/Settings/UISettings.tsx @@ -218,7 +218,10 @@ const UISettings: Component = () => { label="Chat Emphasis Color" fieldName="chatEmphasisColor" helperText={ - userStore.saveCustomUI({ chatEmphasisColor: 'text-600' })}> + userStore.saveCustomUI({ chatEmphasisColor: 'text-600' })} + > Reset to Default } @@ -272,9 +275,13 @@ const UISettings: Component = () => {
{}} isPaneOpen={false} @@ -283,7 +290,11 @@ const UISettings: Component = () => { {}} isPaneOpen={false} diff --git a/web/pages/Settings/Voice/VoiceSettings.tsx b/web/pages/Settings/Voice/VoiceSettings.tsx index 59ce857f5..ab6c0912c 100644 --- a/web/pages/Settings/Voice/VoiceSettings.tsx +++ b/web/pages/Settings/Voice/VoiceSettings.tsx @@ -33,7 +33,9 @@ export const VoiceSettings: Component = () => { when={getSpeechRecognition()} fallback={

Speech to text is not available in your browser

} > -

You can use speech recognition by using the microphone icon in the input text box.

+

+ You can use speech recognition by using the microphone icon in the input text box. +

s.value) || state.user?.hordeWorkers || []} />
-
Workers selected: {selected()?.length || state.user?.hordeWorkers?.length || '0'}
+
+ Workers selected: {selected()?.length || state.user?.hordeWorkers?.length || '0'} +
diff --git a/web/pages/Settings/components/ClaudeSettings.tsx b/web/pages/Settings/components/ClaudeSettings.tsx index 9a433497a..44bfcf92d 100644 --- a/web/pages/Settings/components/ClaudeSettings.tsx +++ b/web/pages/Settings/components/ClaudeSettings.tsx @@ -12,7 +12,9 @@ const ClaudeSettings: Component = () => { label="Claude Key" helperText="Valid Claude Key." placeholder={ - state.user?.claudeApiKeySet ? 'Claude key is set' : 'E.g. sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + state.user?.claudeApiKeySet + ? 'Claude key is set' + : 'E.g. sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' } type="password" value={state.user?.claudeApiKey} diff --git a/web/pages/Settings/components/HordeAISettings.tsx b/web/pages/Settings/components/HordeAISettings.tsx index 62a0f966a..005567fc3 100644 --- a/web/pages/Settings/components/HordeAISettings.tsx +++ b/web/pages/Settings/components/HordeAISettings.tsx @@ -111,7 +111,9 @@ const HordeAISettings: Component<{ fieldName="hordeKey" label="AI Horde API Key" helperText={HordeHelpText} - placeholder={state.user?.hordeName || state.user?.hordeKey ? 'API key has been verified' : ''} + placeholder={ + state.user?.hordeName || state.user?.hordeKey ? 'API key has been verified' : '' + } type="password" value={state.user?.hordeKey} /> @@ -257,8 +259,8 @@ const WorkerModal: Component<{ values={selected()?.map((s) => s.value) || state.user?.hordeWorkers || []} />
- The number showns in brackets are the worker's Max Context Length / Max Tokens limits. If you wish to - use that worker, your preset should not exceed these values. + The number showns in brackets are the worker's Max Context Length / Max Tokens{' '} + limits. If you wish to use that worker, your preset should not exceed these values.
E.g. (1024/80)
diff --git a/web/pages/Settings/components/NovelAISettings.tsx b/web/pages/Settings/components/NovelAISettings.tsx index d053b9057..9e9311e8a 100644 --- a/web/pages/Settings/components/NovelAISettings.tsx +++ b/web/pages/Settings/components/NovelAISettings.tsx @@ -91,9 +91,13 @@ const NovelAISettings: Component = () => { value={''} helperText={ <> - NEVER SHARE THIS WITH ANYBODY! The token from the NovelAI request authorization. Please note this token - expires periodically. You will occasionally need to re-enter this token.{' '} -
+ NEVER SHARE THIS WITH ANYBODY! The token from the NovelAI request authorization. Please + note this token expires periodically. You will occasionally need to re-enter this token.{' '} + Instructions . diff --git a/web/pages/Settings/components/RegisteredSettings.tsx b/web/pages/Settings/components/RegisteredSettings.tsx index 60ea5f114..fd380da1c 100644 --- a/web/pages/Settings/components/RegisteredSettings.tsx +++ b/web/pages/Settings/components/RegisteredSettings.tsx @@ -35,7 +35,9 @@ const ServiceOption: Component<{ config?: Record }> = (props) => { const field = createMemo(() => `adapterConfig.${props.service}.${props.opt.field}`) - const options = createMemo(() => (props.opt.setting.type === 'list' ? props.opt.setting.options : [])) + const options = createMemo(() => + props.opt.setting.type === 'list' ? props.opt.setting.options : [] + ) const isSet = createMemo(() => { const prop = `${props.opt.field}Set` @@ -81,7 +83,12 @@ const ServiceOption: Component<{ - + diff --git a/web/pages/Settings/components/ScaleSettings.tsx b/web/pages/Settings/components/ScaleSettings.tsx index 55bc0e217..34afe2019 100644 --- a/web/pages/Settings/components/ScaleSettings.tsx +++ b/web/pages/Settings/components/ScaleSettings.tsx @@ -18,7 +18,9 @@ const ScaleSettings: Component = () => { diff --git a/web/pages/Settings/index.tsx b/web/pages/Settings/index.tsx index 5540d6a3a..659329a95 100644 --- a/web/pages/Settings/index.tsx +++ b/web/pages/Settings/index.tsx @@ -2,7 +2,12 @@ import { Component, createMemo, createSignal, onMount } from 'solid-js' import { AlertTriangle, Save } from 'lucide-solid' import Button from '../../shared/Button' import PageHeader from '../../shared/PageHeader' -import { applyDotProperty, getFormEntries, getStrictForm, setComponentPageTitle } from '../../shared/util' +import { + applyDotProperty, + getFormEntries, + getStrictForm, + setComponentPageTitle, +} from '../../shared/util' import { settingStore, userStore } from '../../store' import UISettings from './UISettings' import Tabs from '../../shared/Tabs' @@ -143,7 +148,10 @@ const Settings: Component<{ footer?: (children: any) => void }> = (props) => { const tabClass = `flex flex-col gap-4` - const version = (window.agnai_version?.includes('unknown') ? '' : window.agnai_version).slice(0, 7) + const version = (window.agnai_version?.includes('unknown') ? '' : window.agnai_version).slice( + 0, + 7 + ) onMount(() => { props.footer?.(footer) diff --git a/web/shared/Accordian.tsx b/web/shared/Accordian.tsx index 2406fabbd..f39dd1a89 100644 --- a/web/shared/Accordian.tsx +++ b/web/shared/Accordian.tsx @@ -10,7 +10,11 @@ const Accordian: Component<{ const [open, setOpen] = createSignal(props.open ?? true) const cls = createMemo(() => (open() ? '' : 'hidden')) return ( -
+
setOpen(!open())}> }> diff --git a/web/shared/Alert.tsx b/web/shared/Alert.tsx index aebb22e56..eeb983851 100644 --- a/web/shared/Alert.tsx +++ b/web/shared/Alert.tsx @@ -17,11 +17,15 @@ const Alert: Component<{ children: JSX.Element schema: AlertSchema }> = (props) => { - const classes = createMemo(() => [schemaToClasses[props.schema], 'rounded-lg p-4 text-sm flex gap-2'].join(' ')) + const classes = createMemo(() => + [schemaToClasses[props.schema], 'rounded-lg p-4 text-sm flex gap-2'].join(' ') + ) return (