-
-
Notifications
You must be signed in to change notification settings - Fork 106
/
characters.ts
144 lines (119 loc) · 4.13 KB
/
characters.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { assertValid } from '/common/valid'
import { store } from '../../db'
import { errors, handle } from '../wrap'
import { sendMany } from '../ws'
import { AppSchema } from '/common/types'
import { v4 } from 'uuid'
import { now } from '/srv/db/util'
import { entityUploadBase64 } from '../upload'
import { toArray } from '/common/util'
export const addCharacter = handle(async ({ body, params, userId }) => {
assertValid({ charId: 'string' }, body)
const chatId = params.id
const charId = body.charId
const chat = await store.chats.getChatOnly(params.id)
if (!chat) throw errors.NotFound
if (chat.userId !== userId) throw errors.Forbidden
if (!chat.characters) {
chat.characters = {}
}
if (chat.characters[charId]) {
return { success: true }
}
if (charId === chat.characterId) throw errors.BadRequest
const character = await store.characters.getCharacter(userId, charId)
if (!character) throw errors.Forbidden
// TODO: Move query to store module
await store.chats.setChatCharacter(chatId, charId, true)
const members = await store.chats.getActiveMembers(chatId)
sendMany(members.concat(chat.userId), { type: 'chat-character-added', character, chatId })
return { success: true }
})
export const removeCharacter = handle(async ({ params, userId }, _) => {
const chatId = params.id
const charId = params.charId
const chat = await store.chats.getChatOnly(params.id)
if (!chat) throw errors.NotFound
if (chat.userId !== userId) throw errors.Forbidden
if (!chat.characters) {
chat.characters = {}
}
if (!chat.characters[charId]) return { success: true }
await store.chats.setChatCharacter(chatId, charId, false)
const members = await store.chats.getActiveMembers(chatId)
sendMany(members.concat(chat.userId), {
type: 'chat-character-removed',
chatId,
characterId: charId,
})
return { success: true }
})
export const upsertTempCharacter = handle(async ({ body, params, userId }) => {
assertValid(
{
_id: 'string?',
name: 'string',
description: 'string',
appearance: 'string?',
sampleChat: 'string',
persona: 'any',
greeting: 'string',
scenario: 'string',
avatar: 'string?',
favorite: 'boolean?',
deletedAt: 'string?',
voice: 'any?',
systemPrompt: 'string?',
postHistoryInstructions: 'string?',
alternateGreetings: 'any?',
characterBook: 'string?',
visualType: 'string?',
sprite: 'any?',
culture: 'string?',
},
body
)
const chat = await store.chats.getChatOnly(params.id)
if (!chat) throw errors.NotFound
if (chat.userId !== userId) throw errors.Forbidden
const tempCharacters = chat.tempCharacters || {}
const prev = body._id ? tempCharacters[body._id] : null
const upserted: AppSchema.Character = {
_id: body._id || `temp-${v4().slice(0, 8)}`,
kind: 'character',
createdAt: now(),
updatedAt: now(),
userId: chat.userId,
name: body.name,
persona: body.persona,
sampleChat: body.sampleChat,
scenario: body.scenario,
appearance: body.appearance,
avatar: body.avatar || prev?.avatar,
description: body.description,
greeting: body.greeting,
favorite: body.favorite !== undefined ? body.favorite : prev?.favorite,
deletedAt: body.deletedAt,
voice: body.voice,
postHistoryInstructions: body.postHistoryInstructions,
systemPrompt: body.systemPrompt,
alternateGreetings: body.alternateGreetings ? toArray(body.alternateGreetings) : undefined,
characterBook: body.characterBook ? JSON.parse(body.characterBook) : undefined,
visualType: body.visualType,
sprite: body.sprite,
culture: body.culture,
}
tempCharacters[upserted._id] = upserted
const filename = await entityUploadBase64('char', upserted._id, body.avatar)
if (filename) {
upserted.avatar = filename + '?' + v4().slice(0, 4)
}
const members = await store.chats.getActiveMembers(params.id)
await store.chats.update(params.id, { tempCharacters })
sendMany(members.concat(chat.userId), {
type: 'chat-temp-character',
chatId: params.id,
character: upserted,
})
return { success: true, char: upserted }
})