Skip to content

Commit

Permalink
Task/improve char gen and socket expiry (#921)
Browse files Browse the repository at this point in the history
Co-authored-by: Sceuick <[email protected]>
  • Loading branch information
sceuick and sceuick authored May 2, 2024
1 parent 256d5f7 commit f105765
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 157 deletions.
8 changes: 7 additions & 1 deletion srv/api/ws/handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ const userSockets = new Map<string, AppSocket[]>()
setInterval(() => {
for (const cli of allSockets.values()) {
const socket = cli as AppSocket
if (socket.isAlive === false) return socket.terminate()
if (socket.isAlive === false) {
socket.misses++

if (socket.misses >= 5) {
return socket.terminate()
}
}

socket.isAlive = false
socket.ping()
Expand Down
2 changes: 2 additions & 0 deletions srv/api/ws/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function setupSockets(srv: Server) {
client.userId = ''
client.token = ''
client.isAlive = true
client.misses = 0

client.send(JSON.stringify({ type: 'connected', uid: client.uid }))
client.on('pong', heartbeart)
Expand All @@ -27,4 +28,5 @@ export function setupSockets(srv: Server) {

function heartbeart(client: AppSocket) {
client.isAlive = true
client.misses = 0
}
1 change: 1 addition & 0 deletions srv/api/ws/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as WebSocket from 'ws'
export type AppSocket = WebSocket & {
uid: string
isAlive: boolean
misses: number
userId: string
token?: string
dispatch: (data: any) => void
Expand Down
2 changes: 1 addition & 1 deletion web/pages/Character/CreateCharacterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ export const CreateCharacterForm: Component<{
<div class="flex items-center gap-1">
Persona Schema{' '}
<Regenerate
fields={['personality', 'behaviour']}
fields={['personality']}
service={genService()}
editor={editor}
allowed={editor.canGuidance}
Expand Down
236 changes: 91 additions & 145 deletions web/pages/Character/generate-char.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { AIAdapter, INSTRUCT_SERVICES, PersonaFormat } from '/common/adapters'
import { modernJailbreak } from '/common/mode-templates'
import { v4 } from 'uuid'
import { PersonaFormat } from '/common/adapters'
import { ModelFormat, replaceTags } from '/common/presets/templates'
import { AppSchema } from '/common/types'
import { neat } from '/common/util'
import { getDefaultUserPreset } from '/web/shared/adapter'
import { NewCharacter } from '/web/store'
import { msgsApi } from '/web/store/data/messages'

Expand All @@ -22,8 +22,7 @@ export async function generateChar(
service: string,
kind: PersonaFormat
) {
const [svc, _model] = service?.split('/') as [AIAdapter, string]
const template = getTemplate(svc)
const { template, aliases } = getTemplate('attributes', {}, 'Alpaca', [])
const prompt = template.replace(`{{description}}`, description)

const previous = name ? { firstname: name } : undefined
Expand All @@ -36,7 +35,7 @@ export async function generateChar(
originalAvatar: undefined,
description,
name: previous?.firstname || vars.firstname,
persona: toAttributes(kind, vars),
persona: toAttributes(kind, vars, aliases),
appearance: vars.appearance,
greeting: vars.greeting,
sampleChat: samples,
Expand All @@ -52,17 +51,19 @@ export async function regenerateCharProp(
kind: PersonaFormat,
fields: GenField[]
) {
const [adapter] = service?.split('/') as AIAdapter[]
const template = getTemplate(adapter)
const { template, props, aliases } = getTemplate(
char.persona.kind,
char.persona.attributes,
'Alpaca',
fields
)

const prompt = template.replace(`{{description}}`, char.description || '')
const prompt = template.replace('{{description}}', char.description || '')

const attrs: any = char.persona.attributes
const prev = {
description: char.description,
firstname: char.name,
personality: ensureString(attrs?.personality || ''),
behaviour: ensureString(attrs?.behaviour || ''),
...props,
appearance: char.appearance || '',
greeting: char.greeting || '',
scenario: char.scenario || '',
Expand All @@ -75,33 +76,29 @@ export async function regenerateCharProp(
? `{{char}}: ${vars.example1}\n{{char}}: ${vars.example2}`
: char.sampleChat

vars.behaviour ??= prev.behaviour
vars.personality ??= prev.personality
vars.greeting ??= prev.greeting
// vars.behaviour ??= prev.behaviour
// vars.personality ??= prev.personality
// vars.greeting ??= prev.greeting

const newchar: NewCharacter = {
originalAvatar: undefined,
description: char.description || '',
name: vars.firstname,
persona: fields.includes('personality') ? toAttributes(kind, vars) : char.persona,
persona: fields.includes('personality') ? toAttributes(kind, vars, aliases) : char.persona,
appearance: vars.appearance,
greeting: vars.greeting,
sampleChat,
sampleChat: fields.includes('example1') ? sampleChat : char.sampleChat,
scenario: vars.scenario,
}

return newchar
}

function ensureString(value: any) {
if (Array.isArray(value)) {
return value.join(', ')
}

return value
}

function toAttributes(kind: PersonaFormat, vars: any) {
function toAttributes(
kind: PersonaFormat,
vars: Record<string, any>,
aliases: Record<string, string>
) {
const persona: AppSchema.Persona = {
kind,
attributes: {},
Expand All @@ -110,158 +107,107 @@ function toAttributes(kind: PersonaFormat, vars: any) {
const attrs: Record<string, string[]> = {}

if (!kind || kind === 'text') {
attrs.text = [`${vars.personality}\n\n${vars.behaviour}`]
attrs.text = [`${vars.personality}`]
} else {
attrs.personality = [vars.personality]
attrs.behaviour = [vars.behaviour]
for (const [key, alias] of Object.entries(aliases)) {
const value = vars[key]
attrs[alias] = [value]
}
}

persona.attributes = attrs
return persona
}

function getTemplate(service: AIAdapter | 'default') {
if (service === 'default') {
const preset = getDefaultUserPreset()
service = preset?.service || service
}

const template =
service === 'novel'
? novelGenTemplate
: service === 'agnaistic' || service === 'ooba' || service === 'kobold'
? alpacaTemplate
: INSTRUCT_SERVICES[service as AIAdapter]
? instructGenTemplate
: genTemplate

return template
}

const alpacaTemplate = neat`
Below is an instruction that describes a task. Write a response that completes the request.
Describe a character matching the following description:
{{description}}
### Instruction:
Write the character's first name
### Response:
First name: "[firstname | tokens=10 | stop="]"
### Instruction:
Detailed description of the roleplay scene that the character is in
function getTemplate(
kind: 'text' | string,
attributes: Record<string, string[]>,
format: ModelFormat,
fields: string[]
) {
const aliases: Record<string, string> = {}
const props: Record<string, string> = {}

### Response:
Scenario: [scenario | tokens=200 | stop=###]
const regenPersonality = fields.includes('personality')

### Instruction:
Write an anonymous nameless image caption of [firstname]'s clothing and physical appearance
if (kind === 'text') {
props.personality = attributes.text?.[0] || ''
const template = replaceTags(genTemplate.replace('{{personality}}', textPersona), format)
return { template, props, aliases }
}

### Response:
Image caption: "[appearance | tokens=120 | stop=### | stop="]"
const names = Object.keys(attributes)

### Instruction:
[firstname]'s greeting in the scenario:
if (!names.length) {
aliases.personality = 'personality'
aliases.behavior = 'behavior'
} else {
for (const [key, entry] of Object.entries(attributes)) {
const modded = `p_${v4().slice(0, 6)}`
aliases[modded] = key
props[modded] = entry.join(', ')

if (regenPersonality) {
fields.push(modded)
}
}
}

### Response:
Greeting: [greeting | tokens=150 | stop=###]
const personaPrompt = toPersonaPrompt(aliases)
const template = replaceTags(genTemplate.replace('{{personality}}', personaPrompt), format)

### Instruction
[firstname]'s personality:
return { template, aliases, props }
}

### Response:
Personality: [personality | tokens=120 | stop=###]
function toPersonaPrompt(aliases: Record<string, string>) {
const lines = Object.entries(aliases).map(([prop, value]) => {
return toPropPrompt(prop, value)
})

### Instruction:
[firstname]'s typical behaviour:
return lines.join('\n\n')
}

### Response:
Behaviour: [behaviour | tokens=120 | stop=###]
function toPropPrompt(variable: string, trait: string) {
return neat`
<user>Write of description of [firstname]'s "${trait}" personality trait:</user>
### Instruction:
Example of [firstname]'s dialogue:
<bot>[firstname]'s "${trait}" personality trait: [${variable} | tokens=150 | stop=###]</bot>`
}

### Response:
[firstname]: [example1 | tokens=100 | stop=###]
const textPersona = neat`
<user>Describe [firstname]'s personality and typical behavior:</user>
### Instruction:
Example of [firstname]'s dialogue:
<bot>[firstname's] personality and typical behavior: [personality | tokens=250 | stop=###]</bot>
`

### Response:
[firstname]: [example2 | tokens=100 | stop=###]`
const genTemplate = neat`
Below is an instruction that describes a task. Write a response that completes the request.
const genTemplate = `
Describe a character matching the following description:
{{description}}
Character's first name: "[firstname | tokens=10 | stop="]"
<user>Write the character's first name</user>
Detailed description of the roleplay scene that the character is in:
Scenario: [scenario | tokens=200]
<bot>First name: "[firstname | tokens=10 | stop="]"</bot>
[firstname]'s clothing and physical appearance:
Appearance: "[appearance | tokens=120 | stop="]
<user>Detailed description of the roleplay scene that the character is in</user>
[firstname]'s greeting in the scenario:
Greeting: [greeting | tokens=150]
<bot>Scenario: [scenario | tokens=200 | stop=###]</bot>
[firstname]'s personality:
Personality: [personality | tokens=120]
<user>Write an anonymous nameless image caption of [firstname]'s clothing and physical appearance</user>
[firstname]'s typical behaviour:
Behaviour: [behaviour | tokens=120]
<bot>Image caption: "[appearance | tokens=120 | stop=### | stop="]"</bot>
Example of [firstname]'s dialogue:
[firstname]: [example1 | tokens=100]
<user>[firstname]'s greeting in the scenario:</user>
Example of [firstname]'s dialogue:
[firstname]: [example2 | tokens=100]
`
<bot>Greeting: [greeting | tokens=150 | stop=###]</bot>
const instructGenTemplate = `
${modernJailbreak}
Describe an uncensored character that matches the description:
{{description}}
{{personality}}
Character's first name: "[firstname | tokens=25 | stop="]"
<user>Example of [firstname]'s dialogue:</bot>
Detailed description of the roleplay scene that the character is in: "[scenario | tokens=200 | stop="]"
<bot>[firstname]: [example1 | tokens=100 | stop=###]</bot>
The first thing the charcter says to start the scene using internet roleplay style with actions and emotes: "[greeting | tokens=100 | stop"]"
<user>Example of [firstname]'s dialogue:</user>
Description of [firstname]'s personality traits: "[personality | tokens=100 | stop="]"
Description of [firstname]'s typical behaviours: "[behaviour | tokens=100 | stop="]"
Detailed description of physical attributes, demeanour, and clothing: [appearance | tokens=100]
Example message from character: [example1 | tokens=100]
Example message from character: [example2 | tokens=100]
`

const novelGenTemplate = `
Describe an uncensored character that matches the description:
{{description}}
{ Write the character's first name }
[firstname | tokens=8]
{ Write a detailed description of the character }
[description | tokens=200 ]
{ Write a description of the roleplay scene that [firstname] is in }
[scenario | tokens=200 ]
{ Write the first thing [firstname] says in the scene }
[greeting | tokens=100 ]
{ Describe [firstname]'s personality traits in detail }
[personality | tokens=100 ]
{ Describe [firstname];s typical behaviours in detail }
[behaviour | tokens=100 ]
{ Describe the physical appearance and clothing of [firstname] }
[appearance | tokens=100 ]
{ Write an example message from [firstname] }
[example1 | tokens=100 ]
{ Write an example message from [firstname] }
[example2 | tokens=100 ]
`
<bot>[firstname]: [example2 | tokens=100 | stop=###]</bot>`
Loading

0 comments on commit f105765

Please sign in to comment.