talemate/talemate_frontend/src/components/WorldStateManagerCharacter.vue
veguAI 95a17197ba
0.26.0 (#133)
* implement manually disabling and enabling clients

* relock

* fix warning spam

* start moving stuff around

* move more stuff

* start separating world state manager into more managable submodules

* character title

* scroll home to top always

* finish separating character state editor into components

* fix defered nav to character sections

* separate components for pin and contextdb managing

* fix issue with context character filter search

* fix world state manage ux state reset issues

* wsm menu refactor
allow updating character image from wsm
cover image layout fixes

* remove debug spam

* fix client deletion / disabling rubber banding issue

* deactivate / activate / delete characters through wsm

* reload character instead

* fix koboldcpp client jiggle arguments

* save scene title

* fix deferred nav

* fix issue where blanking a character detail would bug out

* some layout changes

* character import copies cover image

* remove debug message

* character import via wsm

* deactivate imported characters

* images nav option placeholder

* start move towards new world state templating system

* prompt tweak

* add templates/world-state/*.yaml

* switch to new world state template system in manager

* template editor progress

* more wsm template changes

* template applicator component

* template applicate added to attributes and details

* selective template application

* fix issue with template editing

* attribute and detail templates dont require instructions

* adjust character attributes and details template applicator integration

* add gpt-4o

add gpt-4o-2024-05-13

* autocomplete prompt and postprocessing tweaks

* prompt tweaks

* fix issue where saving a new scene could cause recent config changes to revert

* only download punkt if its not downloaded yet

* working character attribute templates

* character detail generate working
move template generate logic to worldstate.templates

* character creator first steps

* support contextual generate when character doesn't exist

* move talemate wsm templates to their own dir, add supports_spice and supports_style flags

* wsm character creator progress

* character creator progress

* character creator progress and wire up image creation in character editor

* templating progress

* contextual generate generation options

* ux tweaks

* wirte up writing style and spice to generation

* wire spice / writing style to detail generation

* notify when spice is applied

* tweaks to generation spice notifications

* add some help / information to template editor

* fix some issues with detail and attribute generation

* some context gen tweaks

* character gen tweaks

* character color changer

* link to templates form gen option ux

* gen options for dialogue example genrate

* ctrl click to max spice level

* unify spice application notification into a component for reuse

* improvements to example dialogue generation

* some refinements to character editor

* remove some old cruft from scene schema

* wsm scene editor progress

* relock

* relock

* debug message cleanup

* fix issue with tab selection when loading a scene

* scene editor progress

* centralized generation options

* pass generation settings through to character creator

* save changes from wsm view

* scene settings
save copy

* refactor world entry / states editor

* fix issue with applying non-character world state templates

* layout fixes

* allow updating of scene cover image

* move history manager to world editor

* add phi-3 base template

* dialogue cleanup improvements

* refactor scoped game-engine api

* separate legacy creator functions to own file

* remove cruft

* some cleanup and fixes

* add photo style

* remove noisy log message

* better handling of active scene

* some fixes to pin editor

* don't enforce height

* active scene context fixes

* fix intro and scene description generration

* tweak preset for scene direction and summarization tasks

* ensure memory db is open

* update frontend dependencies

* update frontend dependencies

* fix issue with prompt query_memory function returning None

* typo

* default  world state templates

* new scene creation fixes
remove legacy creator ux

* scene export

* fix scene loading from upload

* add claude 3.5 sonnet

* fix automatic client selection when the current client is disabled

* remove cruft

* agent modal extended to support multiple config panels
visual agent prompt prefixes and suffixes addeed

* fix issue with world state template group saving

* resolve attribute name issue `copy`

* RequestInput: fix form validation and keystroke submit

* support chara load from json files also refactor character loading to load.py

* implement simple act-as feature using tab to cycle through active characters in the scene

* docs progress

* tts settings tweaks

* fix issue with loading older talemate scenes

* docs progress

* fix issue with config validation on new installs

* some tweaks for agent setting modals

* default template changed to alpaca

* docs dependencies

* gemma2 template

* nemotron4 template

* docs

* docs

* docs

* change prompt template section to autocomplete

* fix agent config not loading for some agents

* allow deletion of player character

* fix some oddities with scene outline commit

* automatically active player characters and create player characters with the correct actor class

* also set the first npc created as immediately acitve

* add has_active_npcs property and re-emit message history when scene outline is updated.

* indicate when visualizer is busy in the scene tools

* check for busy instead

* prompt tweaks for movie script type dialogue format

* gemma2 prompt fixed

* scene message colors updated

* act as narrator

* move to _old

* scene message appearance tweaks

* fix rubberbanding when editing text field in agent configs

* fix autocompletionm when acting as different character or narrator

* disable autocomplete during command execution

* remove autocomplete button from scene tools

* docs

* relock

* docs

* docs

* improve context pins in dialogue context

* better approximate token count

* fix pin condition editing

* fix issue where scene save as would lose long term memory entries

* immediately clean message history when loading a new scene

* docs

* ensure intro text has formatting markers

* narrator messages written by the player can now be deleted.

* scene editor

* move docs around

* start character editor docs

* more character editor docs:

* fix some ux bugs

* fix template group deletrion not removing the file

* docs

* typos

* docs

* relock

* docs

* notify image generation errors

* linting

* gh pages workflow

* use poetry

* dont use poetry

* link to docs site

* set site_url

* add trailing slash

* fix image paths

* re-add tabbyai link

* fix image generation error triggering incorrectly

* fix intro formatting incosistencies

* remove cruft

* add time passed label to history view

* date adjustments

* tests

* add gpt-4o-mini

* fix links

* remove hard ntlk requirement for voice generation chunking

ntlk error handling

fix typo

* docs

* fix issdue with dupe character card intro text

* disable character forms while templates are being applied.

* failure during context generate no longer locks ux

* refactor client and agent status display in system bar

* llama 3.1 8b claude

* fix format

* adjustments to automcomplete dialogue instructions

* add mistral nemo

* debug info

* fix system agent status getting stuck

* readme

* readme

* fix autocomplete responses when they are framed by quotes
2024-07-26 21:43:06 +03:00

429 lines
No EOL
21 KiB
Vue

<template>
<v-card flat>
<div v-if="selected !== null && character">
<v-card-title>
<v-icon size="small">mdi-account</v-icon>
{{ character.name }}
<v-chip size="x-small" v-if="character.is_player === false" color="warning" label>AI</v-chip>
<v-chip size="x-small" v-if="character.is_player === true" color="info" label>Player</v-chip>
<v-chip size="x-small" class="ml-1" v-if="character.active === true && character.is_player === false" color="success" label>Active</v-chip>
<v-tooltip text="Change the name color for this character." v-if="!character.is_new">
<template v-slot:activator="{ props }">
<v-chip v-bind="props" size="x-small" label class="ml-1" :style="`color: ${character.color}`" prepend-icon="mdi-brush" @click.stop="characterColorPicker=true" variant="tonal">{{ character.color }}</v-chip>
</template>
</v-tooltip>
<v-dialog v-model="characterColorPicker" scrollable width="300">
<v-color-picker v-model="character.color" @update:model-value="onCharacterColorChange"></v-color-picker>
</v-dialog>
</v-card-title>
</div>
<div v-else-if="character && character.is_new">
<v-card-title>
<v-icon size="small">mdi-account-plus</v-icon>
Create New Character
</v-card-title>
</div>
<v-card-text>
<div v-if="character && character.is_new">
<WorldStateManagerCharacterCreator
ref="creator"
@require-scene-save="$emit('require-scene-save')"
@cancelled="reset"
@character-created="onCharacterCreated"
:generation-options="generationOptions"
:scene="scene"
:templates="templates" />
</div>
<div v-else-if="selected !== null && character">
<v-row>
<v-col cols="12" md="3" xl="2">
<CoverImage v-if="character !== null" ref="coverImageCharacter" :target="character" :type="'character'" :allow-update="true" :collapsable="false" />
<p v-if="coverImageBusy">
<v-progress-linear color="primary" height="2" indeterminate></v-progress-linear>
</p>
<v-list v-if="character !== null">
<!-- GENERATE COVER IMAGE -->
<v-list-item>
<v-tooltip max-width="300" :text="`Generate a new cover image for ${character.name}. This will be used as the main image for the character.`">
<template v-slot:activator="{ props }">
<v-btn :disabled="!agentStatus.visual || !agentStatus.visual.ready" @click.stop="visualizeCharacter" v-bind="props" variant="tonal" block color="primary" prepend-icon="mdi-image-filter-center-focus">Generate Image</v-btn>
</template>
</v-tooltip>
</v-list-item>
</v-list>
<v-list v-if="character !== null">
<!-- DEACTIVATE CHARACTER -->
<div v-if="!character.is_player">
<v-list-item v-if="character.active">
<v-tooltip max-width="300" :text="`Immediately deactivate ${character.name}. This will remove the character from the scene, but it will still be available in the character list, and can be recalled at any point.`">
<template v-slot:activator="{ props }">
<v-btn @click.stop="deactivateCharacter" v-bind="props" variant="tonal" block color="secondary" prepend-icon="mdi-exit-run">Deactivate</v-btn>
</template>
</v-tooltip>
</v-list-item>
<v-list-item v-else>
<v-tooltip max-width="300" :text="`Immediately activate ${character.name}. This will re-add them to the scene and allow to participate in it.`">
<template v-slot:activator="{ props }">
<v-btn @click.stop="activateCharacter" v-bind="props" variant="tonal" block color="primary" prepend-icon="mdi-human-greeting">Activate</v-btn>
</template>
</v-tooltip>
</v-list-item>
</div>
<v-divider></v-divider>
<!-- DELETE CHARACTER -->
<v-list-item>
<v-tooltip v-if="confirmDelete === null" max-width="300" :text="`Permanently delete ${character.name} - will ask for confirmation and cannot be undone.`">
<template v-slot:activator="{ props }">
<v-btn @click.stop="confirmDelete=''" variant="tonal" v-bind="props" block color="red-darken-2" prepend-icon="mdi-close-box-outline">Delete</v-btn>
</template>
</v-tooltip>
<div v-else class="mt-2">
<v-list-item-subtitle>Confirm Deletion</v-list-item-subtitle>
<p class="text-grey text-caption">
Confirm that you want to delete <span class="text-primary">{{ character.name }}</span>, by
typing the character name and clicking <span class="text-red-darken-2">Delete</span> once more.
This cannot be undone.
</p>
<v-text-field :disabled="deleteBusy" v-model="confirmDelete" color="red-darken-2" hide-details @keydown.enter="deleteCharacter" />
<v-btn v-if="confirmDelete !== character.name" :disabled="deleteBusy" variant="tonal" block color="secondary" prepend-icon="mdi-cancel" @click.stop="confirmDelete = null">Cancel</v-btn>
<v-btn v-else :disabled="deleteBusy" variant="tonal" block color="red-darken-2" prepend-icon="mdi-close-box-outline" @click.stop="deleteCharacter">Delete</v-btn>
</div>
</v-list-item>
</v-list>
</v-col>
<v-col cols="12" md="9" xl="10">
<v-card>
<v-tabs v-model="page" color="primary" density="compact">
<v-tab value="description">
<v-icon size="small">mdi-text-account</v-icon>
Description
</v-tab>
<v-tab value="attributes">
<v-icon size="small">mdi-format-list-bulleted-type</v-icon>
Attributes
</v-tab>
<v-tab value="details">
<v-icon size="small">mdi-format-list-text</v-icon>
Details
</v-tab>
<v-tab value="reinforce">
<v-icon size="small">mdi-image-auto-adjust</v-icon>
States
</v-tab>
<v-tab value="actor" :disabled="character.is_player">
<v-icon size="small">mdi-bullhorn</v-icon>
Actor
</v-tab>
<!--
<v-tab value="actor" :disabled="true">
<v-icon size="small">mdi-image</v-icon>
Images
</v-tab>
-->
</v-tabs>
<v-divider></v-divider>
<v-card-text>
<v-tabs-window v-model="page">
<v-tabs-window-item value="description">
<WorldStateManagerCharacterDescription
ref="description"
@require-scene-save="$emit('require-scene-save')"
:generation-options="generationOptions"
:templates="templates"
:immutable-character="character" />
</v-tabs-window-item>
<v-tabs-window-item value="attributes">
<WorldStateManagerCharacterAttributes
ref="attributes"
@require-scene-save="$emit('require-scene-save')"
:generation-options="generationOptions"
:templates="templates"
:immutable-character="character" />
</v-tabs-window-item>
<v-tabs-window-item value="details">
<WorldStateManagerCharacterDetails
ref="details"
@require-scene-save="$emit('require-scene-save')"
@load-character-state-reinforcement="onLoadCharacterStateReinforcement"
:generation-options="generationOptions"
:templates="templates"
:immutable-character="character" />
</v-tabs-window-item>
<v-tabs-window-item value="reinforce">
<WorldStateManagerCharacterReinforcements
ref="reinforcements"
@require-scene-save="$emit('require-scene-save')"
:templates="templates"
:immutable-character="character" />
</v-tabs-window-item>
<v-tabs-window-item value="actor">
<WorldStateManagerCharacterActor
ref="reinforcements"
@require-scene-save="$emit('require-scene-save')"
:generation-options="generationOptions"
:templates="templates"
:character="character" />
</v-tabs-window-item>
</v-tabs-window>
</v-card-text>
</v-card>
</v-col>
</v-row>
</div>
<v-alert v-else type="info" color="grey" variant="text" icon="mdi-account">
<p>
Manage existing characters or add new ones to the scene. Characters can be AI or player controlled.
</p>
<p class="mt-2">
You can set up character attributes, descriptions, and details.
You can also set up automatic reinforcement of character states. This will cause the
AI to regularly re-evaluate the state and update the detail accordingly.
</p>
<p class="mt-2">
Select a character from the list on the left to get started.
</p>
</v-alert>
</v-card-text>
</v-card>
<v-card class="mt-4" density="compact" v-if="character === null">
<v-card-title>Overview</v-card-title>
<v-card-text class="text-grey">
<p class="mt-4">
<!-- Attribute description -->
<strong class="text-grey-lighten-1">
<v-icon size="small" class="mr-2" color="highlight1">mdi-badge-account</v-icon>Attributes
</strong> are low to medium detail information about the character. They range from physical attributes to personality traits.
</p>
<p class="mt-4">
<!-- Details description -->
<strong class="text-grey-lighten-1">
<v-icon size="small" class="mr-2" color="highlight2">mdi-account-details</v-icon>Details
</strong> are low to high detail information about the character. They could contain information about the character's background, history, or other relevant information.
</p>
<p class="mt-2 text-muted">
When a <v-icon size="small" class="mr-2" color="highlight3">mdi-image-auto-adjust</v-icon><span class="text-highlight3">state reinforcment</span> is updated the value is set to the corresponding detail.
</p>
<p class="mt-4">
<!-- Character description description -->
<strong class="text-grey-lighten-1">
<v-icon size="small" class="mr-2" color="grey">mdi-text-account</v-icon>Description
</strong> is a description of the character. A summarization of their appearance, personality, and other relevant information as it relates to the scene.
</p>
<p class="mt-4">
<!-- Reinforcement description -->
<strong class="text-grey-lighten-1">
<v-icon size="small" class="mr-2" color="highlight3">mdi-image-auto-adjust</v-icon>States
</strong> are the reinforcement states for the character. This is where you can set up automatic reinforcement of character states. This will cause the AI to regularly re-evaluate the state and update the detail accordingly.
</p>
<p class="mt-4">
<!-- Actor description -->
<strong class="text-grey-lighten-1">
<v-icon size="small" class="mr-2" color="highlight5">mdi-bullhorn</v-icon>Actor
</strong> management lets you define acting and speaking patterns for the character via dialogue instructions and examples. This is only available for AI characters.
</p>
</v-card-text>
</v-card>
</template>
<script>
import CoverImage from './CoverImage.vue';
import WorldStateManagerCharacterAttributes from './WorldStateManagerCharacterAttributes.vue';
import WorldStateManagerCharacterDescription from './WorldStateManagerCharacterDescription.vue';
import WorldStateManagerCharacterDetails from './WorldStateManagerCharacterDetails.vue';
import WorldStateManagerCharacterReinforcements from './WorldStateManagerCharacterReinforcements.vue';
import WorldStateManagerCharacterActor from './WorldStateManagerCharacterActor.vue';
import WorldStateManagerCharacterCreator from './WorldStateManagerCharacterCreator.vue';
export default {
name: 'WorldStateManagerCharacter',
components: {
CoverImage,
WorldStateManagerCharacterAttributes,
WorldStateManagerCharacterDescription,
WorldStateManagerCharacterDetails,
WorldStateManagerCharacterReinforcements,
WorldStateManagerCharacterActor,
WorldStateManagerCharacterCreator,
},
props: {
scene: Object,
characterList: Object,
templates: Object,
agentStatus: Object,
generationOptions: Object,
},
inject: [
'getWebsocket',
'registerMessageHandler',
],
data() {
return {
page: 'description',
selected: null,
character: null,
confirmDelete: null,
deleteBusy: false,
coverImageBusy: false,
characterColorPicker: false,
}
},
emits:[
'require-scene-save',
'selected-character',
],
methods: {
reset() {
this.selected = null;
this.character = null;
this.page = 'description';
if(this.$refs.attributes)
this.$refs.attributes.reset()
},
onLoadCharacterStateReinforcement(name) {
this.page = 'reinforce'
this.$nextTick(() => {
this.$refs.reinforcements.loadWithRequire(name);
});
},
onCharacterCreated(character) {
this.$nextTick(() => {
this.selected = character.name;
});
},
onCharacterColorChange() {
this.getWebsocket().send(JSON.stringify({
type: 'world_state_manager',
action: 'update_character_color',
name: this.character.name,
color: this.character.color,
}));
},
requestCharacter(name) {
this.getWebsocket().send(JSON.stringify({
type: 'world_state_manager',
action: 'get_character_details',
name: name,
}));
},
newCharacter(character) {
this.character = character;
this.$nextTick(() => {
this.$refs.creator.setCharacter(character)
});
},
loadCharacter(name) {
this.requestCharacter(name);
this.page = 'description';
this.selected = name;
},
selectCharacter(name) {
this.loadCharacter(name);
this.selected = name;
},
deleteCharacter() {
if (this.confirmDelete === this.character.name) {
this.deleteBusy = true;
this.getWebsocket().send(JSON.stringify({
type: 'world_state_manager',
action: 'delete_character',
name: this.character.name,
}));
}
},
deactivateCharacter() {
this.getWebsocket().send(JSON.stringify({
type: 'world_state_manager',
action: 'deactivate_character',
name: this.character.name,
}));
},
activateCharacter() {
this.getWebsocket().send(JSON.stringify({
type: 'world_state_manager',
action: 'activate_character',
name: this.character.name,
}));
},
visualizeCharacter() {
this.coverImageBusy = true;
this.getWebsocket().send(JSON.stringify({
type: 'visual',
action: 'visualize_character',
context: {
character_name: this.character.name,
replace: true,
}
}));
},
handleMessage(message) {
if(message.type == "image_generated") {
this.coverImageBusy = false;
if(message.data.context.character_name === this.character.name) {
this.loadCharacter(this.character.name);
}
}
else if (message.type === 'image_generation_failed'){
this.coverImageBusy = false;
}
else if (message.type !== 'world_state_manager') {
return;
}
else if (message.action === 'character_details') {
this.character = message.data;
this.$emit('selected-character', this.character)
} else if(message.action === 'character_deleted') {
if(this.selected === message.data.name) {
this.reset();
}
this.deleteBusy = false;
this.confirmDelete = null;
} else if(message.action === 'character_deactivated' || message.action === 'character_activated') {
if(this.selected === message.data.name) {
this.loadCharacter(this.selected)
}
}
},
},
created() {
this.registerMessageHandler(this.handleMessage);
},
}
</script>