Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions srv/api/chat/inference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const validInference = {
presetId: 'string?',
jsonSchema: 'any?',
imageData: 'string?',
chatId: 'string?',
} as const

const validInferenceApi = {
Expand Down Expand Up @@ -414,6 +415,7 @@ export const inferenceStream = wrap(async (req, res) => {
imageData: body.imageData,
stop: body.stop,
signal,
chatId: body.chatId,
})

const requestId = body.requestId || v4()
Expand Down
2 changes: 2 additions & 0 deletions srv/api/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getThirdPartyPresetModels,
testConnectionUrl,
getUserPreset,
getChatPreset,
} from './presets'
import { hordeStats, novelLogin, openRouterModels, updateService } from './services'
import {
Expand Down Expand Up @@ -80,6 +81,7 @@ router.get('/init', loggedIn, getInitialLoad)
router.get('/', loggedIn, getProfile)
router.get('/presets', loggedIn, getUserPresets)
router.get('/presets/:id', loggedIn, getUserPreset)
router.get('/presets/:id/chat', loggedIn, getChatPreset)
router.get('/templates', loggedIn, getPromptTemplates)
router.delete('/presets/:id/key', loggedIn, deleteUserPresetKey)
router.get('/config', loggedIn, getConfig)
Expand Down
37 changes: 36 additions & 1 deletion srv/api/user/presets.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { assertValid } from '/common/valid'
import { defaultPresets, presetValidator } from '../../../common/presets'
import { defaultPresets, getFallbackPreset, presetValidator } from '../../../common/presets'
import { store } from '../../db'
import { StatusError, handle } from '../wrap'
import { AIAdapter } from '../../../common/adapters'
import { AppSchema } from '/common/types'
import { toSamplerOrder } from '/common/sampler-order'
import { decryptText } from '/srv/db/util'
import { getThirdPartyModels } from '/common/requests/util'
import { isDefaultPreset } from '/common/default-preset'
import { deepClone } from '/common/util'

const createPreset = {
...presetValidator,
Expand Down Expand Up @@ -96,6 +98,39 @@ export const getUserPreset = handle(async ({ userId, params }) => {
return preset
})

export const getChatPreset = handle(async ({ userId, params }) => {
const chat = await store.chats.getChatOnly(params.id)
if (!chat) {
throw new StatusError(`Preset not found (Invalid chat id)`, 404)
}

if (!chat.genPreset) {
return getFallbackPreset('agnaistic')
}

if (isDefaultPreset(chat.genPreset)) {
const copy = deepClone(defaultPresets[chat.genPreset])
return copy
}

const preset = await store.presets.getSafeUserPreset(chat.genPreset, userId)
if (!preset) {
const fallback = getFallbackPreset('agnaistic')
return fallback
}

if (userId === preset.userId) {
return preset
}

const members = await store.chats.getActiveMembers(params.id)
if (!members.includes(userId)) {
throw new StatusError(`Preset not found: Not allowed`, 402)
}

return preset
})

export const getBasePresets = handle(async () => {
return { presets: defaultPresets }
})
Expand Down
2 changes: 1 addition & 1 deletion web/pages/Character/CharacterSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const CharacterSchema: Component<{

if (props.characterId) {
const char = ctx.allBots[props.characterId]
json = char ? char.json : chatStore.getState().active?.char.json
json = char ? char.json : ctx.char?.json
} else if (props.presetId || props.inherit) {
json = props.inherit || activePreset()?.json
}
Expand Down
10 changes: 6 additions & 4 deletions web/pages/Chat/ChatDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ const ChatDetail: Component = () => {
const [_, presetSet] = usePresetContext()

const chats = chatStore((s) => ({
...(s.active?.chat._id === params.id ? s.active : undefined),
...(ctx.active?.chat._id === params.id ? ctx.active : undefined),
lastId: s.lastChatId,
members: s.chatProfiles,
loaded: s.detailLoaded,
loading: s.detailLoading,

opts: s.opts,
linesAddedCount: s.prompt?.template.linesAddedCount,
msgVisibility: s.msgVisibility,
Expand Down Expand Up @@ -213,11 +214,12 @@ const ChatDetail: Component = () => {
return nav(`/chat/${chats.lastId}`)
}

if (params.id !== chats.chat?._id) {
if (params.id !== chats.lastId) {
presetSet.loadChatId(params.id)
presetStore.getTemplates(true)
chatStore.openChat(params.id, {
onDone: async (success, chat) => {
if (success && chat) {
await Promise.all([presetSet.loadChat(chat, true), presetStore.getTemplates(true)])
return
}

Expand Down Expand Up @@ -425,7 +427,7 @@ const ChatDetail: Component = () => {
swipe={swipe()}
/>
}
loading={!chats.loaded && !chats.chat}
loading={!ctx.active}
showPane={showPane()}
pane={<ChatPanes />}
split={split()}
Expand Down
6 changes: 4 additions & 2 deletions web/pages/Chat/ChatExport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import Button from '../../shared/Button'
import Modal from '../../shared/Modal'
import { characterStore, chatStore, msgStore } from '../../store'
import { resolveChatPath } from '/common/chat'
import { useAppContext } from '/web/store/context'

const ChatExport: Component<{ show: boolean; close: () => void }> = (props) => {
const [ctx] = useAppContext()
const chats = chatStore.getState()
const chars = characterStore.getState().characters
const msgs = msgStore.getState()

const json = createMemo(() => {
const graph = msgs.graph
const chat = chats.active?.chat
const chat = ctx.active?.chat
const messages = resolveChatPath(graph.tree, msgs.msgs.slice(-1)[0]._id)

const json = {
Expand Down Expand Up @@ -52,7 +54,7 @@ const ChatExport: Component<{ show: boolean; close: () => void }> = (props) => {
</Button>
<a
href={`data:text/json:charset=utf-8,${json()}`}
download={`chat-${chats.active?.chat._id.slice(0, 4)}.json`}
download={`chat-${ctx.active?.chat._id.slice(0, 4)}.json`}
onClick={props.close}
>
<Button>
Expand Down
8 changes: 4 additions & 4 deletions web/pages/Chat/ChatFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ export const ChatFooter: Component<{
const chars = characterStore((s) => ({ botMap: s.characters.map }))
const chats = chatStore((s) => ({
opts: s.opts,
char: s.active?.char,
chat: s.active?.chat,
replyAs: s.active?.replyAs,
participantIds: s.active?.participantIds,
char: props.ctx.active?.char,
chat: props.ctx.active?.chat,
replyAs: props.ctx.active?.replyAs,
participantIds: props.ctx.active?.participantIds,
members: s.chatProfiles,
}))

Expand Down
10 changes: 5 additions & 5 deletions web/pages/Chat/ChatOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const ChatOptions: Component<{
togglePane: (pane: ChatRightPane) => void
}> = (props) => {
const chats = chatStore((s) => ({
...s.active,
active: s.details[s.lastChatId || ''],
opts: s.opts,
members: s.chatProfiles,
}))
Expand All @@ -53,7 +53,7 @@ const ChatOptions: Component<{
}

const isOwner = createMemo(
() => chats.chat?.userId === user.user?._id && chats.chat?.mode !== 'companion'
() => chats.active?.chat?.userId === user.user?._id && chats.active?.chat?.mode !== 'companion'
)

const screenshotChat = async () => {
Expand Down Expand Up @@ -87,8 +87,8 @@ const ChatOptions: Component<{

return (
<>
<Show when={chats.chat?.mode}>
<Card>Mode: {chats.chat?.mode}</Card>
<Show when={chats.active?.chat?.mode}>
<Card>Mode: {chats.active?.chat?.mode}</Card>
</Show>
<div class="flex w-72 flex-col gap-2 p-2">
<Show when={chats.members.length > 1}>
Expand Down Expand Up @@ -152,7 +152,7 @@ const ChatOptions: Component<{
</Item>
</Row>

<Show when={chats.chat}>
<Show when={chats.active?.chat}>
<Row>
<Item
onClick={() => {
Expand Down
34 changes: 17 additions & 17 deletions web/pages/Chat/ChatSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ const ChatSettings: Component<{
close: () => void
footer: (children: any) => void
}> = (props) => {
const state = chatStore((s) => ({ chat: s.active?.chat, char: s.active?.char }))
const state = chatStore((s) => ({ active: s.details[s.lastChatId || ''] }))
const [generating, setGenerating] = createSignal('')
const [flags, setFlags] = createSignal<Record<string, boolean>>({})
const [edit, setEdit] = createStore(getInitState(state.chat, state.char))
const [edit, setEdit] = createStore(getInitState(state.active?.chat, state.active?.char))

const user = userStore((s) => ({ user: s.user }))
const presets = presetStore((s) => ({ list: s.presets }))
Expand All @@ -95,7 +95,7 @@ const ChatSettings: Component<{

const saveBackgroundImage = async (files: FileInputResult[]) => {
if (!files?.length) return
if (!state.chat) return
if (!state.active?.chat) return

const [file] = files

Expand All @@ -114,7 +114,7 @@ const ChatSettings: Component<{
})

const activePreset = createMemo(() => {
const presetId = state.chat?.genPreset
const presetId = state.active?.chat?.genPreset
if (!presetId) return

if (isDefaultPreset(presetId)) return defaultPresets[presetId]
Expand All @@ -123,10 +123,10 @@ const ChatSettings: Component<{

createEffect(
on(
() => [state.chat, state.char] as const,
() => [state.active?.chat, state.active?.char] as const,
([chat, char]) => {
if (!chat || !char) return
setFlags(state.chat?.invisible ? { ...state.chat.invisible } : {})
setFlags(state.active?.chat?.invisible ? { ...state.active?.chat.invisible } : {})
setEdit(getInitState(chat, char))
}
)
Expand All @@ -137,7 +137,7 @@ const ChatSettings: Component<{
})

createEffect(() => {
setEdit('scenarioId', state.chat?.scenarioIds?.[0] || '')
setEdit('scenarioId', state.active?.chat?.scenarioIds?.[0] || '')
})

createEffect(
Expand All @@ -148,7 +148,7 @@ const ChatSettings: Component<{
const scenario = scenarioState.scenarios.find((s) => s._id === edit.scenarioId)
if (
scenario?.overwriteCharacterScenario &&
!state.chat?.scenarioIds?.includes(scenario._id)
!state.active?.chat?.scenarioIds?.includes(scenario._id)
) {
setEdit('scenario', scenario.text)
} else {
Expand All @@ -162,7 +162,7 @@ const ChatSettings: Component<{
const noScenario = [{ value: '', label: "None (use character's scenario)" }]
if (scenarioState.loading || scenarioState.partial) {
return noScenario.concat(
(state.chat?.scenarioIds ?? []).map((id) => ({
(state.active?.chat?.scenarioIds ?? []).map((id) => ({
value: id,
label: '...',
}))
Expand All @@ -189,7 +189,7 @@ const ChatSettings: Component<{
genOverrideField({
char: {
name: edit.name,
appearance: state.char?.appearance || '',
appearance: state.active?.char?.appearance || '',
description: edit.description || '',

greeting: edit.greeting,
Expand Down Expand Up @@ -229,7 +229,7 @@ const ChatSettings: Component<{
const flag = next[charId] === undefined ? true : !next[charId]
next[charId] = flag
setFlags(next)
chatStore.editChat(state.chat?._id!, { invisible: next }, { quiet: true })
chatStore.editChat(state.active?.chat?._id!, { invisible: next }, { quiet: true })
}

const onSave = () => {
Expand All @@ -248,7 +248,7 @@ const ChatSettings: Component<{
scenarioIds: edit.scenarioId ? [edit.scenarioId] : [],
scenarioStates: edit.scenarioStates,
}
chatStore.editChat(state.chat?._id!, payload, {
chatStore.editChat(state.active?.chat?._id!, payload, {
useOverrides: edit.useOverrides,
onSuccess: () => {
if (pane() !== 'pane') {
Expand All @@ -259,10 +259,10 @@ const ChatSettings: Component<{
}

const revert = () => {
const char = state.char
const char = state.active?.char
if (!char) return

chatStore.editChat(state.chat?._id!, {})
chatStore.editChat(state.active?.chat?._id!, {})
}

const Footer = (
Expand All @@ -288,7 +288,7 @@ const ChatSettings: Component<{
return (
<form class="flex flex-col gap-3">
<Show when={user.user?.admin}>
<Card class="text-xs">{state.chat?._id}</Card>
<Card class="text-xs">{state.active?.chat?._id}</Card>
</Show>

<Card>
Expand All @@ -315,7 +315,7 @@ const ChatSettings: Component<{
<div class="flex items-center justify-between gap-1">
Background Image{' '}
<div class="flex items-center gap-1">
<Show when={state.chat?.background}>
<Show when={state.active?.chat?.background}>
<Select
parentClass="text-xs"
items={[
Expand Down Expand Up @@ -346,7 +346,7 @@ const ChatSettings: Component<{
label="Chat Mode"
helperText={
<>
<Show when={state.chat?.mode !== 'companion' && edit.mode === 'companion'}>
<Show when={state.active?.chat?.mode !== 'companion' && edit.mode === 'companion'}>
<TitleCard type="orange">
Warning! Switching to COMPANION mode is irreversible! You will no longer be able
to: retry messages, delete chats, edit chat settings.
Expand Down
11 changes: 7 additions & 4 deletions web/pages/Chat/MemberModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ const ParticipantsList: Component<{
edit: (charId: string) => void
}> = (props) => {
const self = userStore((s) => ({ user: s.user, profile: s.profile }))
const state = chatStore((s) => ({ active: s.active }))
const state = chatStore((s) => ({ active: s.details[s.lastChatId] }))

const lists = useParticipantList()

Expand Down Expand Up @@ -265,7 +265,7 @@ const ParticipantsList: Component<{
}

const AddCharacter: Component<{ setView: (view: View) => {} }> = (props) => {
const state = chatStore((s) => ({ active: s.active }))
const state = chatStore((s) => ({ active: s.details[s.lastChatId] }))
const chars = characterStore((s) => ({ characters: s.characters }))

onMount(() => {
Expand Down Expand Up @@ -316,7 +316,7 @@ const AddCharacter: Component<{ setView: (view: View) => {} }> = (props) => {

const InviteUser: Component<{ setView: (view: View) => {} }> = (props) => {
let ref: any
const state = chatStore((s) => ({ active: s.active }))
const state = chatStore((s) => ({ active: s.details[s.lastChatId] }))

const [userId, setUserId] = createSignal('')

Expand Down Expand Up @@ -505,7 +505,10 @@ export function useParticipantList(forChat?: boolean) {
impersonating: s.impersonating,
characters: forChat ? s.chatChars : s.characters,
}))
const state = chatStore((s) => ({ active: s.active, memberIds: s.memberIds }))
const state = chatStore((s) => ({
active: s.details[s.lastChatId || ''],
memberIds: s.memberIds,
}))

const charMembers = createMemo<AppSchema.Character[]>(() => {
const active = getActiveBots(
Expand Down
Loading