Skip to content

Commit

Permalink
Adds TavernAI chat log import (single bot/user only) (#91)
Browse files Browse the repository at this point in the history
Co-authored-by: Sceuick <leikho@gmail.com>
  • Loading branch information
khanonnie and sceuick committed Mar 27, 2023
1 parent 5ba15f9 commit 85df245
Show file tree
Hide file tree
Showing 16 changed files with 380 additions and 54 deletions.
62 changes: 40 additions & 22 deletions srv/api/chat/create.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { assertValid } from 'frisker'
import { PERSONA_FORMATS } from '../../../common/adapters'
import { store } from '../../db'
import { NewMessage } from '../../db/messages'
import { handle, StatusError } from '../wrap'

export const createChat = handle(async ({ body, user }) => {
Expand All @@ -22,25 +23,42 @@ export const createChat = handle(async ({ body, user }) => {
return chat
})

// export const importChat = handle(async ({ body, userId }) => {
// assertValid(
// {
// characterId: 'string',
// name: 'string',
// greeting: 'string',
// scenario: 'string',
// overrides: {
// kind: PERSONA_FORMATS,
// attributes: 'any',
// },
// messages: [{ msg: 'string', characterId: 'string?', userId: 'string?' }],
// },
// body
// )

// const character = await store.characters.getCharacter(userId!, body.characterId)

// if (!character) {
// throw new StatusError(`Character not found`, 404)
// }
// })
export const importChat = handle(async ({ body, userId }) => {
assertValid(
{
characterId: 'string',
name: 'string',
greeting: 'string',
scenario: 'string',
messages: [{ msg: 'string', characterId: 'string?', userId: 'string?' }],
},
body
)

const character = await store.characters.getCharacter(userId!, body.characterId)

if (!character) {
throw new StatusError(`Character not found`, 404)
}

const chat = await store.chats.create(body.characterId, {
name: body.name,
greeting: body.greeting,
scenario: body.scenario,
overrides: character.persona,
sampleChat: '',
userId,
})

const messages = body.messages.map<NewMessage>((msg) => ({
chatId: chat._id,
message: msg.msg,
adapter: 'import',
characterId: msg.characterId ? character._id : undefined,
senderId: msg.userId ? userId : undefined,
}))

await store.msgs.importMessages(messages)

return chat
})
6 changes: 4 additions & 2 deletions srv/api/chat/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Router } from 'express'
import { loggedIn } from '../auth'
import { createChat } from './create'
import { createChat, importChat } from './create'
import { updateChat, updateChatGenPreset, updateChatGenSettings, updateMessage } from './edit'

import { getAllChats, getCharacterChats, getChatDetail } from './get'
Expand All @@ -18,12 +18,14 @@ router.use(loggedIn)
router.get('/', getAllChats)
router.get('/invites', getInvites)
router.get('/:id/messages', getMessages)
router.post('/', createChat)
router.get('/:id', getChatDetail)

router.put('/:id', updateChat)
router.put('/:id/generation', updateChatGenSettings)
router.put('/:id/preset', updateChatGenPreset)

router.post('/', createChat)
router.post('/import', importChat)
router.post('/:id/invite', createInvite)
router.post('/:inviteId/accept', acceptInvite)
router.post('/:inviteId/reject', rejectInvite)
Expand Down
5 changes: 5 additions & 0 deletions srv/api/chat/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export const generateMessageV2 = handle(async ({ userId, body, socketId, params,
}

if (userId) {
if (body.kind === 'retry' && userId !== chat.userId) {
throw errors.Forbidden
}

if (body.kind === 'continue' && userId !== chat.userId) {
throw errors.Forbidden
}
Expand Down Expand Up @@ -202,6 +206,7 @@ function newMessage(
}
return userMsg
}

/**
* V1 response generation routes
* To be removed
Expand Down
2 changes: 1 addition & 1 deletion srv/api/wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type Handler = (req: AppRequest, res: express.Response, next: express.Nex

export type AppRequest = Omit<express.Request, 'log'> & {
user?: AppSchema.Token
userId?: string
userId: string
log: AppLog
socketId: string
}
Expand Down
20 changes: 20 additions & 0 deletions srv/db/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export type NewMessage = {
adapter?: string
}

export type ImportedMessage = NewMessage & { createdAt: string }

export async function createChatMessage(
{ chatId, message, characterId, senderId, adapter }: NewMessage,
ephemeral?: boolean
Expand All @@ -34,6 +36,24 @@ export async function createChatMessage(
return doc
}

export async function importMessages(messages: NewMessage[]) {
const docs: AppSchema.ChatMessage[] = messages.map((msg) => ({
_id: v4(),
kind: 'chat-message',
rating: 'none',
chatId: msg.chatId,
characterId: msg.characterId,
userId: msg.senderId,
msg: msg.message,
adapter: msg.adapter,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}))

await db('chat-message').insertMany(docs)
return docs
}

export async function getMessage(messageId: string) {
const msg = await db('chat-message').findOne({ _id: messageId, kind: 'chat-message' })
return msg
Expand Down
2 changes: 2 additions & 0 deletions srv/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export namespace AppSchema {

defaultAdapter: AIAdapter
defaultPresets?: { [key in AIAdapter]?: string }

createdAt?: string
}

export interface Chat {
Expand Down
1 change: 1 addition & 0 deletions srv/db/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export async function createUser(newUser: NewUser, admin?: boolean) {
hordeKey: '',
oaiKey: '',
defaultPresets: {},
createdAt: new Date().toISOString(),
}

const startChar: AppSchema.Character = {
Expand Down
9 changes: 8 additions & 1 deletion web/pages/Character/ChatList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { Component, createEffect, createSignal, For, Show } from 'solid-js'
import { characterStore, chatStore } from '../../store'
import PageHeader from '../../shared/PageHeader'
import Button from '../../shared/Button'
import { Plus, Trash } from 'lucide-solid'
import { Import, Plus, Trash } from 'lucide-solid'
import CreateChatModal from './CreateChat'
import ImportChatModal from './ImportChat'
import { toDuration, toEntityMap } from '../../shared/util'
import { ConfirmModal } from '../../shared/Modal'
import { AppSchema } from '../../../srv/db/schema'
Expand All @@ -13,6 +14,7 @@ import AvatarIcon from '../../shared/AvatarIcon'
const CharacterChats: Component = () => {
const { id } = useParams()
const [showCreate, setCreate] = createSignal(false)
const [showImport, setImport] = createSignal(false)

const state = chatStore((s) => {
if (id) {
Expand All @@ -37,6 +39,10 @@ const CharacterChats: Component = () => {
</Show>

<div class="flex w-full justify-end gap-2">
<Button onClick={() => setImport(true)}>
<Import />
Import
</Button>
<Button onClick={() => setCreate(true)}>
<Plus />
Chat
Expand All @@ -52,6 +58,7 @@ const CharacterChats: Component = () => {
char={state.char}
id={id}
/>
<ImportChatModal show={showImport()} close={() => setImport(false)} char={state.char} />
</div>
)
}
Expand Down
Loading

0 comments on commit 85df245

Please sign in to comment.