feat: character card support

This commit is contained in:
Timothy J. Baek 2024-06-17 02:26:07 -07:00
parent f1b350cbe6
commit ab62228877
6 changed files with 66 additions and 13 deletions

14
package-lock.json generated
View File

@ -34,6 +34,7 @@
"sortablejs": "^1.15.2", "sortablejs": "^1.15.2",
"svelte-sonner": "^0.3.19", "svelte-sonner": "^0.3.19",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"turndown": "^7.2.0",
"uuid": "^9.0.1" "uuid": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
@ -1000,6 +1001,11 @@
"svelte": ">=3 <5" "svelte": ">=3 <5"
} }
}, },
"node_modules/@mixmark-io/domino": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -9077,6 +9083,14 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/turndown": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz",
"integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==",
"dependencies": {
"@mixmark-io/domino": "^2.2.0"
}
},
"node_modules/tweetnacl": { "node_modules/tweetnacl": {
"version": "0.14.5", "version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",

View File

@ -74,6 +74,7 @@
"sortablejs": "^1.15.2", "sortablejs": "^1.15.2",
"svelte-sonner": "^0.3.19", "svelte-sonner": "^0.3.19",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"turndown": "^7.2.0",
"uuid": "^9.0.1" "uuid": "^9.0.1"
} }
} }

View File

@ -9,6 +9,7 @@
import Suggestions from '../MessageInput/Suggestions.svelte'; import Suggestions from '../MessageInput/Suggestions.svelte';
import { sanitizeResponseContent } from '$lib/utils'; import { sanitizeResponseContent } from '$lib/utils';
import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -41,14 +42,23 @@
selectedModelIdx = modelIdx; selectedModelIdx = modelIdx;
}} }}
> >
<img <Tooltip
crossorigin="anonymous" content={marked.parse(
src={model?.info?.meta?.profile_image_url ?? sanitizeResponseContent(models[selectedModelIdx]?.info?.meta?.description)
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)} )}
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none" placement="right"
alt="logo" >
draggable="false" <img
/> crossorigin="anonymous"
src={model?.info?.meta?.profile_image_url ??
($i18n.language === 'dg-DG'
? `/doge.png`
: `${WEBUI_BASE_URL}/static/favicon.png`)}
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
draggable="false"
/>
</Tooltip>
</button> </button>
{/each} {/each}
</div> </div>

View File

@ -126,7 +126,7 @@
: selected : selected
? 'from-gray-100 dark:from-gray-950' ? 'from-gray-100 dark:from-gray-950'
: 'invisible group-hover:visible from-gray-100 dark:from-gray-950'} : 'invisible group-hover:visible from-gray-100 dark:from-gray-950'}
absolute right-[10px] top-[10px] pr-2 pl-5 bg-gradient-to-l from-80% absolute right-[10px] top-[6px] py-1 pr-2 pl-5 bg-gradient-to-l from-80%
to-transparent" to-transparent"
on:mouseenter={(e) => { on:mouseenter={(e) => {

View File

@ -4,6 +4,8 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { settings, user, config, models, tools } from '$lib/stores'; import { settings, user, config, models, tools } from '$lib/stores';
import TurndownService from 'turndown';
import { onMount, tick, getContext } from 'svelte'; import { onMount, tick, getContext } from 'svelte';
import { addNewModel, getModelById, getModelInfos } from '$lib/apis/models'; import { addNewModel, getModelById, getModelInfos } from '$lib/apis/models';
import { getModels } from '$lib/apis'; import { getModels } from '$lib/apis';
@ -14,6 +16,7 @@
import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte'; import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte';
import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte'; import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte';
import { stringify } from 'postcss'; import { stringify } from 'postcss';
import { parseFile } from '$lib/utils/characters';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -60,7 +63,10 @@
let knowledge = []; let knowledge = [];
$: if (name) { $: if (name) {
id = name.replace(/\s+/g, '-').toLowerCase(); id = name
.replace(/\s+/g, '-')
.replace(/[^a-zA-Z0-9-]/g, '')
.toLowerCase();
} }
const addUsage = (base_model_id) => { const addUsage = (base_model_id) => {
@ -213,9 +219,29 @@
accept="image/*" accept="image/*"
on:change={() => { on:change={() => {
let reader = new FileReader(); let reader = new FileReader();
reader.onload = (event) => { reader.onload = async (event) => {
let originalImageUrl = `${event.target.result}`; let originalImageUrl = `${event.target.result}`;
let character = await parseFile(inputFiles[0]).catch((error) => {
return null;
});
if (character && character.character) {
character = character.character;
console.log(character);
name = character.name;
const turndownService = new TurndownService();
info.meta.description = turndownService.turndown(character.summary);
info.params.system = `Personality: ${character.personality}${
character?.scenario ? `\nScenario: ${character.scenario}` : ''
}${character?.greeting ? `\First Message: ${character.greeting}` : ''}${
character?.examples ? `\nExamples: ${character.examples}` : ''
}`;
}
const img = new Image(); const img = new Image();
img.src = originalImageUrl; img.src = originalImageUrl;
@ -408,10 +434,11 @@
</div> </div>
{#if info.meta.description !== null} {#if info.meta.description !== null}
<input <textarea
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg" class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Add a short description about what this model does')} placeholder={$i18n.t('Add a short description about what this model does')}
bind:value={info.meta.description} bind:value={info.meta.description}
row="3"
/> />
{/if} {/if}
</div> </div>

View File

@ -369,10 +369,11 @@
</div> </div>
{#if info.meta.description !== null} {#if info.meta.description !== null}
<input <textarea
class="mt-1 px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg" class="mt-1 px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Add a short description about what this model does')} placeholder={$i18n.t('Add a short description about what this model does')}
bind:value={info.meta.description} bind:value={info.meta.description}
row="3"
/> />
{/if} {/if}
</div> </div>