Skip to content

Commit

Permalink
Feat/character schemas (#990)
Browse files Browse the repository at this point in the history
- Add feature flag for google sign in
- Add toggle for google sign in
- fix swapping if message is empty
- Openrouter: add streaming and samplers
- Show horde image wait time
- Ollama ui fields and min_p
  • Loading branch information
sceuick authored Aug 4, 2024
1 parent a59d79b commit e1b5a0a
Show file tree
Hide file tree
Showing 65 changed files with 1,134 additions and 294 deletions.
2 changes: 2 additions & 0 deletions common/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ type NoId<T> = Omit<T, '_id' | 'kind'>
type OmitId<T, U extends string> = Omit<T, '_id' | 'kind' | U>

type Dates = 'createdAt' | 'updatedAt' | 'deletedAt' | 'kind'

declare type Ensure<T> = Exclude<T, null | undefined>
26 changes: 22 additions & 4 deletions common/horde-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type Fetcher = <T = any>(
opts: FetchOpts
) => Promise<{ statusCode?: number; statusMessage?: string; body: T }>

type HordeCheck = {
export type HordeCheck = {
generations: any[]
done: boolean
faulted: boolean
Expand All @@ -38,6 +38,8 @@ type HordeCheck = {
kudos: number
wait_time: number
message?: string
processing: number
shared: boolean
}

let TIMEOUT_SECS = Infinity
Expand Down Expand Up @@ -86,12 +88,14 @@ type GenerateOpts = {
payload: any
timeoutSecs?: number
key: string
onTick?: (status: HordeCheck) => void
}

export async function generateImage(
user: AppSchema.User,
prompt: string,
negative: string,
onTick: (status: HordeCheck) => void,
log: AppLog = logger
) {
const base = user.images
Expand Down Expand Up @@ -121,7 +125,12 @@ export async function generateImage(
log?.debug({ ...payload, prompt: null }, 'Horde payload')
log?.debug(`Prompt:\n${payload.prompt}`)

const image = await generate({ type: 'image', payload, key: user.hordeKey || HORDE_GUEST_KEY })
const image = await generate({
type: 'image',
payload,
key: user.hordeKey || HORDE_GUEST_KEY,
onTick,
})
return image
}

Expand Down Expand Up @@ -206,7 +215,7 @@ async function generate(opts: GenerateOpts) {
? `${baseUrl}/generate/text/status/${init.body.id}`
: `${baseUrl}/generate/status/${init.body.id}`

const result = await poll(url, opts.key, opts.type === 'text' ? 2.5 : 6.5)
const result = await poll(url, opts.key, opts.type === 'text' ? 2.5 : 6.5, opts.onTick)

if (!result.generations || !result.generations.length) {
const error: any = new Error(`Horde request failed: No generation received`)
Expand All @@ -218,7 +227,12 @@ async function generate(opts: GenerateOpts) {
return { text, result }
}

async function poll(url: string, key: string | undefined, interval = 6.5) {
async function poll(
url: string,
key: string | undefined,
interval: number,
onTick?: (status: HordeCheck) => void
) {
const started = Date.now()
const threshold = TIMEOUT_SECS * 1000

Expand All @@ -237,6 +251,10 @@ async function poll(url: string, key: string | undefined, interval = 6.5) {
throw error
}

if (!res.body.generations?.length) {
onTick?.(res.body)
}

if (res.body.faulted) {
throw new Error(`Horde request failed: The worker faulted while generating.`)
}
Expand Down
59 changes: 25 additions & 34 deletions common/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,8 @@ function fillPlaceholders(opts: {
user: string
}): string {
const prefix = opts.msg.system ? 'System' : opts.author
const msg = opts.msg.msg.replace(BOT_REPLACE, opts.char).replace(SELF_REPLACE, opts.user)
const text = opts.msg.json?.history || opts.msg.msg
const msg = text.replace(BOT_REPLACE, opts.char).replace(SELF_REPLACE, opts.user)

return `${prefix}: ${msg}`
}
Expand Down Expand Up @@ -985,15 +986,19 @@ export type JsonType = { title?: string; description?: string; valid?: string }
| { type: 'bool' }
)

export type JsonProps = Record<string, JsonType>

export type JsonSchema = {
title: string
type: 'object'
properties: JsonProps
properties: Record<string, JsonType>
required: string[]
}

export interface JsonField {
name: string
disabled: boolean
type: JsonType
}

export const schema = {
str: (o?: { desc?: string; title?: string; maxLength?: number }) => ({
type: 'string',
Expand All @@ -1019,7 +1024,7 @@ export const schema = {
}),
} satisfies Record<string, (...args: any[]) => JsonType>

export function toJsonSchema(body: JsonProps): JsonSchema {
export function toJsonSchema(body: JsonField[]): JsonSchema {
const schema: JsonSchema = {
title: 'Response',
type: 'object',
Expand All @@ -1029,39 +1034,25 @@ export function toJsonSchema(body: JsonProps): JsonSchema {

const props: JsonSchema['properties'] = {}

for (let [key, def] of Object.entries(body)) {
key = key.replace(/_/g, ' ')
props[key] = { ...def }
for (const { name, disabled, type } of body) {
if (disabled) continue
props[name] = { ...type }
delete props[name].valid

delete props[key].valid
if (def.type === 'bool') {
props[key].type = 'enum'
if (type.type === 'bool') {
props[name].type = 'enum'

// @ts-ignore
props[key].enum = ['true', 'false', 'yes', 'no']
}
schema.required.push(name)
}

schema.properties = props
schema.required = Object.keys(props)
return schema
}

type ToJsonPrimitive<T extends JsonType> = T['type'] extends 'string'
? string
: T['type'] extends 'integer'
? number
: T['type'] extends 'bool'
? boolean
: string[]

type JsonValid<T extends JsonProps> = { [key in keyof T]: ToJsonPrimitive<T[key]> }

export function fromJsonResponse<T extends JsonProps>(
schema: T,
response: any,
output: any = {}
): JsonValid<T> {
export function fromJsonResponse(schema: JsonField[], response: any, output: any = {}): any {
const json: Record<string, any> = tryJsonParseResponse(response)

for (let [key, value] of Object.entries(json)) {
Expand All @@ -1071,16 +1062,16 @@ export function fromJsonResponse<T extends JsonProps>(
key = underscored
}

const def = schema[key]
const def = schema.find((s) => s.name === key)
if (!def) continue

output[key] = value
if (def.type === 'bool') {
if (def.type.type === 'bool') {
output[key] = value.trim() === 'true' || value.trim() === 'yes'
}
}

return output as JsonValid<T>
return output
}

export function tryJsonParseResponse(res: string) {
Expand All @@ -1105,11 +1096,11 @@ export function tryJsonParseResponse(res: string) {
return {}
}

export function onJsonTickHandler<T extends JsonProps>(
schema: T,
handler: (res: Partial<JsonValid<T>>, state: InferenceState) => void
export function onJsonTickHandler(
schema: JsonField[],
handler: (res: any, state: InferenceState) => void
) {
let curr: Partial<JsonValid<T>> = {}
let curr: any = {}
const parser: TickHandler = (res, state) => {
if (state === 'done') {
const body = fromJsonResponse(schema, tryJsonParseResponse(res))
Expand Down
10 changes: 10 additions & 0 deletions common/types/library.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PersonaFormat } from '../adapters'
import { JsonField } from '../prompt'
import { BaseImageSettings, ImageSettings } from './image-schema'
import { MemoryBook } from './memory'
import { FullSprite } from './sprite'
Expand Down Expand Up @@ -45,6 +46,8 @@ export interface Character extends BaseCharacter {

image?: ImageSettings

json?: CharacterJsonSchema

folder?: string
// v2 stuff
alternateGreetings?: string[]
Expand All @@ -68,3 +71,10 @@ export interface LibraryCharacter extends Omit<Character, 'kind' | 'tags'> {
chats: number
messages: number
}

export interface CharacterJsonSchema {
schema: JsonField[]
response: string
history: string
enabled: boolean
}
7 changes: 1 addition & 6 deletions common/types/presets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { AIAdapter, OpenRouterModel, ThirdPartyFormat } from '../adapters'
import { ModelFormat } from '../presets/templates'
import { JsonProps } from '../prompt'
import { BaseImageSettings } from './image-schema'

export interface SubscriptionTier {
Expand Down Expand Up @@ -105,6 +104,7 @@ export interface GenSettings {
banEosToken?: boolean
tokenHealing?: boolean

disableNameStops?: boolean
earlyStopping?: boolean
stopSequences?: string[]
trimStop?: boolean
Expand Down Expand Up @@ -137,11 +137,6 @@ export interface GenSettings {
ignoreCharacterUjb?: boolean
antiBond?: boolean

json?: {
schema: JsonProps
template: string
}

frequencyPenalty?: number
presencePenalty?: number
oaiModel?: string
Expand Down
10 changes: 8 additions & 2 deletions common/types/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type { UISettings } from './ui'
import * as Saga from './saga'
import * as Library from './library'
import * as Preset from './presets'
import type { JsonProps } from '../prompt'
import type { JsonField } from '../prompt'

export type AllDoc =
| AppSchema.Announcement
Expand Down Expand Up @@ -98,6 +98,7 @@ export namespace AppSchema {
imagesModels: ImageModel[]

googleClientId: string
googleEnabled: boolean

ttsHost: string
ttsApiKey: string
Expand All @@ -109,7 +110,7 @@ export namespace AppSchema {
modPresetId: string
modPrompt: string
modFieldPrompt: string
modSchema: JsonProps
modSchema: JsonField[]

charlibPublish: 'off' | 'users' | 'subscribers' | 'moderators' | 'admins'
charlibGuidelines: string
Expand Down Expand Up @@ -409,6 +410,11 @@ export namespace AppSchema {
state?: string
values?: Record<string, string | number | boolean>
parent?: string
json?: {
response: string
history: string
values: any
}
}

export type ScenarioEventType = 'world' | 'character' | 'hidden' | 'ooc'
Expand Down
Loading

0 comments on commit e1b5a0a

Please sign in to comment.