[feat] added horde support, added spec2 requirements that didn't implemented
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import { customProviderStore, getCurrentPluginMax } from "src/ts/process/plugins";
|
||||
import { isTauri } from "src/ts/globalApi";
|
||||
import { tokenize } from "src/ts/tokenizer";
|
||||
import ModelList from "src/lib/UI/ModelList.svelte";
|
||||
import DropList from "src/lib/SideBars/DropList.svelte";
|
||||
import { PlusIcon, TrashIcon } from "lucide-svelte";
|
||||
let tokens = {
|
||||
@@ -36,40 +37,10 @@
|
||||
|
||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.chatBot}</h2>
|
||||
<span class="text-neutral-200 mt-4">{language.model} <Help key="model"/></span>
|
||||
<select class="bg-transparent input-text mt-2 mb-2 text-gray-200 appearance-none text-sm" bind:value={$DataBase.aiModel}>
|
||||
<optgroup class="bg-darkbg appearance-none" label="OpenAI">
|
||||
<option value="gpt35" class="bg-darkbg appearance-none">OpenAI GPT-3.5</option>
|
||||
<option value="gpt4" class="bg-darkbg appearance-none">OpenAI GPT-4</option>
|
||||
</optgroup>
|
||||
<optgroup class="bg-darkbg appearance-none" label="Other Providers">
|
||||
<option value="palm2" class="bg-darkbg appearance-none">Google Palm2</option>
|
||||
{#if $DataBase.aiModel === 'novelai' || isTauri}
|
||||
<option value="novelai" class="bg-darkbg appearance-none">NovelAI Clio</option>
|
||||
{/if}
|
||||
<option value="textgen_webui" class="bg-darkbg appearance-none">Text Generation WebUI</option>
|
||||
{#if $DataBase.plugins.length > 0}
|
||||
<option value="custom" class="bg-darkbg appearance-none">Plugin</option>
|
||||
{/if}
|
||||
</optgroup>
|
||||
</select>
|
||||
|
||||
<ModelList bind:value={$DataBase.aiModel}/>
|
||||
<span class="text-neutral-200 mt-2">{language.submodel} <Help key="submodel"/></span>
|
||||
<select class="bg-transparent input-text mt-2 mb-2 text-gray-200 appearance-none text-sm" bind:value={$DataBase.subModel}>
|
||||
<optgroup class="bg-darkbg appearance-none" label="OpenAI">
|
||||
<option value="gpt35" class="bg-darkbg appearance-none">OpenAI GPT-3.5</option>
|
||||
<option value="gpt4" class="bg-darkbg appearance-none">OpenAI GPT-4</option>
|
||||
</optgroup>
|
||||
<optgroup class="bg-darkbg appearance-none" label="Other Providers">
|
||||
<option value="palm2" class="bg-darkbg appearance-none">Google Palm2</option>
|
||||
{#if $DataBase.aiModel === 'novelai' || isTauri}
|
||||
<option value="novelai" class="bg-darkbg appearance-none">NovelAI Clio</option>
|
||||
{/if}
|
||||
<option value="textgen_webui" class="bg-darkbg appearance-none">Text Generation WebUI</option>
|
||||
{#if $DataBase.plugins.length > 0}
|
||||
<option value="custom" class="bg-darkbg appearance-none">Plugin</option>
|
||||
{/if}
|
||||
</optgroup>
|
||||
</select>
|
||||
<ModelList bind:value={$DataBase.subModel}/>
|
||||
|
||||
|
||||
{#if $DataBase.aiModel === 'palm2' || $DataBase.subModel === 'palm2'}
|
||||
<span class="text-neutral-200">Palm2 {language.apiKey}</span>
|
||||
@@ -96,6 +67,12 @@
|
||||
<span class="text-neutral-200">NovelAI Bearer Token</span>
|
||||
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected text-sm mb-2" bind:value={$DataBase.novelai.token}>
|
||||
|
||||
{/if}
|
||||
|
||||
{#if $DataBase.aiModel.startsWith("horde") || $DataBase.subModel.startsWith("horde") }
|
||||
<span class="text-neutral-200">Horde {language.apiKey}</span>
|
||||
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected text-sm mb-2" bind:value={$DataBase.hordeConfig.apiKey}>
|
||||
|
||||
{/if}
|
||||
{#if $DataBase.aiModel === 'textgen_webui' || $DataBase.subModel === 'textgen_webui'}
|
||||
<span class="text-neutral-200">TextGen {language.providerURL} <Help key="oogaboogaURL"/></span>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import RegexData from "./RegexData.svelte";
|
||||
import { exportChar } from "src/ts/characterCards";
|
||||
import { getElevenTTSVoices, getWebSpeechTTSVoices } from "src/ts/process/tts";
|
||||
import { checkCharOrder } from "src/ts/globalApi";
|
||||
import { checkCharOrder } from "src/ts/globalApi";
|
||||
|
||||
let subMenu = 0
|
||||
let subberMenu = 0
|
||||
@@ -181,10 +181,10 @@
|
||||
<span class="text-neutral-200">{language.firstMessage} <Help key="charFirstMessage"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 text-xs resize-none h-20 focus:bg-selected" autocomplete="off" bind:value={currentChar.data.firstMessage}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.firstMsg} {language.tokens}</span>
|
||||
<span class="text-neutral-200">{language.authorNote} <Help key="charNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.postHistoryInstructions}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.charaNote} {language.tokens}</span>
|
||||
|
||||
<span class="text-neutral-200">{language.authorNote} <Help key="chatNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].note}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.localNote} {language.tokens}</span>
|
||||
|
||||
{:else}
|
||||
<input class="text-neutral-200 mt-2 mb-4 p-2 bg-transparent input-text text-xl focus:bg-selected" placeholder="Group Name" bind:value={currentChar.data.name}>
|
||||
<span class="text-neutral-200">{language.character}</span>
|
||||
@@ -213,11 +213,6 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="text-neutral-200">{language.chatNotes} <Help key="charNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].note}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.localNote} {language.tokens}</span>
|
||||
|
||||
|
||||
{/if}
|
||||
|
||||
<div class="flex mt-6 items-center">
|
||||
@@ -520,10 +515,7 @@
|
||||
<span class="text-neutral-200">{language.systemPrompt} <Help key="systemPrompt"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 text-xs resize-none h-20 focus:bg-selected" autocomplete="off" bind:value={currentChar.data.systemPrompt}></textarea>
|
||||
|
||||
<span class="text-neutral-200">{language.chatNotes} <Help key="chatNote"/></span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 resize-none h-20 focus:bg-selected text-xs" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].note}></textarea>
|
||||
<span class="text-gray-400 mb-6 text-sm">{tokens.localNote} {language.tokens}</span>
|
||||
|
||||
|
||||
{#if currentChar.data.chats[currentChar.data.chatPage].supaMemoryData && currentChar.data.chats[currentChar.data.chatPage].supaMemoryData.length > 4}
|
||||
<span class="text-neutral-200">{language.SuperMemory}</span>
|
||||
<textarea class="bg-transparent input-text mt-2 mb-2 text-gray-200 text-xs resize-none h-20 focus:bg-selected" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].supaMemoryData}></textarea>
|
||||
|
||||
35
src/lib/UI/ModelList.svelte
Normal file
35
src/lib/UI/ModelList.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { DataBase } from "src/ts/database";
|
||||
import { isTauri } from "src/ts/globalApi";
|
||||
import { getHordeModels } from "src/ts/horde/getModels";
|
||||
|
||||
export let value = ""
|
||||
</script>
|
||||
|
||||
{#await getHordeModels()}
|
||||
<select class="bg-transparent input-text mt-2 mb-2 text-gray-200 appearance-none text-sm" value="">
|
||||
<option value="" class="bg-darkbg appearance-none">Loading...</option>
|
||||
</select>
|
||||
{:then models}
|
||||
<select class="bg-transparent input-text mt-2 mb-2 text-gray-200 appearance-none text-sm" bind:value>
|
||||
<optgroup class="bg-darkbg appearance-none" label="OpenAI">
|
||||
<option value="gpt35" class="bg-darkbg appearance-none">OpenAI GPT-3.5</option>
|
||||
<option value="gpt4" class="bg-darkbg appearance-none">OpenAI GPT-4</option>
|
||||
</optgroup>
|
||||
<optgroup class="bg-darkbg appearance-none" label="Other Providers">
|
||||
<option value="palm2" class="bg-darkbg appearance-none">Google Palm2</option>
|
||||
{#if value === 'novelai' || isTauri}
|
||||
<option value="novelai" class="bg-darkbg appearance-none">NovelAI Clio</option>
|
||||
{/if}
|
||||
<option value="textgen_webui" class="bg-darkbg appearance-none">Text Generation WebUI</option>
|
||||
{#if $DataBase.plugins.length > 0}
|
||||
<option value="custom" class="bg-darkbg appearance-none">Plugin</option>
|
||||
{/if}
|
||||
</optgroup>
|
||||
<optgroup class="bg-darkbg appearance-none" label="Horde">
|
||||
{#each models as model}
|
||||
<option value={"horde:::" + model} class="bg-darkbg appearance-none">{model}</option>
|
||||
{/each}
|
||||
</optgroup>
|
||||
</select>
|
||||
{/await}
|
||||
@@ -203,7 +203,8 @@ function convertOldTavernAndJSON(charaData:OldTavernChar, imgp:string|undefined
|
||||
characterVersion: 0,
|
||||
personality: charaData.personality ?? '',
|
||||
scenario:charaData.scenario ?? '',
|
||||
firstMsgIndex: -1
|
||||
firstMsgIndex: -1,
|
||||
replaceGlobalNote: ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +382,7 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
mode: "normal",
|
||||
alwaysActive: book.constant ?? false,
|
||||
selective: book.selective ?? false,
|
||||
extentions: book.extensions
|
||||
extentions: {...book.extensions, risu_case_sensitive: book.case_sensitive}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -412,7 +413,7 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
exampleMessage: data.mes_example ?? '',
|
||||
creatorNotes:data.creator_notes ?? '',
|
||||
systemPrompt:data.system_prompt ?? '',
|
||||
postHistoryInstructions:data.post_history_instructions ?? '',
|
||||
postHistoryInstructions:'',
|
||||
alternateGreetings:data.alternate_greetings ?? [],
|
||||
tags:data.tags ?? [],
|
||||
creator:data.creator ?? '',
|
||||
@@ -428,7 +429,8 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise<boole
|
||||
creator: data.creator,
|
||||
character_version: data.character_version
|
||||
},
|
||||
additionalAssets: extAssets
|
||||
additionalAssets: extAssets,
|
||||
replaceGlobalNote: data.post_history_instructions ?? ''
|
||||
}
|
||||
|
||||
db.characters.push(char)
|
||||
@@ -458,7 +460,8 @@ export async function exportSpecV2(char:character) {
|
||||
constant: lore.alwaysActive,
|
||||
selective:lore.selective,
|
||||
name: lore.comment,
|
||||
comment: lore.comment
|
||||
comment: lore.comment,
|
||||
case_sensitive: lore.extentions?.risu_case_sensitive
|
||||
})
|
||||
}
|
||||
|
||||
@@ -474,7 +477,7 @@ export async function exportSpecV2(char:character) {
|
||||
mes_example: char.exampleMessage,
|
||||
creator_notes: char.creatorNotes,
|
||||
system_prompt: char.systemPrompt,
|
||||
post_history_instructions: char.postHistoryInstructions,
|
||||
post_history_instructions: char.replaceGlobalNote,
|
||||
alternate_greetings: char.alternateGreetings,
|
||||
character_book: {
|
||||
scan_depth: char.loreSettings?.scanDepth,
|
||||
@@ -625,5 +628,5 @@ interface charBookEntry{
|
||||
secondary_keys?: Array<string> // see field `selective`. ignored if selective == false
|
||||
constant?: boolean // if true, always inserted in the prompt (within budget limit)
|
||||
position?: 'before_char' | 'after_char' // whether the entry is placed before or after the character defs
|
||||
|
||||
case_sensitive?:boolean
|
||||
}
|
||||
@@ -275,7 +275,6 @@ export function characterFormatUpdate(index:number|character){
|
||||
cha.exampleMessage = cha.exampleMessage ?? ''
|
||||
cha.creatorNotes = cha.creatorNotes ?? ''
|
||||
cha.systemPrompt = cha.systemPrompt ?? ''
|
||||
cha.postHistoryInstructions = cha.postHistoryInstructions ?? ''
|
||||
cha.tags = cha.tags ?? []
|
||||
cha.creator = cha.creator ?? ''
|
||||
cha.characterVersion = cha.characterVersion ?? 0
|
||||
@@ -288,6 +287,12 @@ export function characterFormatUpdate(index:number|character){
|
||||
character_version: 0
|
||||
}
|
||||
|
||||
if(cha.postHistoryInstructions){
|
||||
cha.chats[cha.chatPage].note += "\n" + cha.postHistoryInstructions
|
||||
cha.chats[cha.chatPage].note = cha.chats[cha.chatPage].note.trim()
|
||||
cha.postHistoryInstructions = null
|
||||
}
|
||||
|
||||
}
|
||||
if(checkNullish(cha.customscript)){
|
||||
cha.customscript = []
|
||||
@@ -332,7 +337,8 @@ export function createBlankChar():character{
|
||||
characterVersion: 0,
|
||||
personality:"",
|
||||
scenario:"",
|
||||
firstMsgIndex: -1
|
||||
firstMsgIndex: -1,
|
||||
replaceGlobalNote: ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +259,9 @@ export interface loreBook{
|
||||
mode: 'multiple'|'constant'|'normal',
|
||||
alwaysActive: boolean
|
||||
selective:boolean
|
||||
extentions?:{}
|
||||
extentions?:{
|
||||
risu_case_sensitive:boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface character{
|
||||
@@ -303,6 +305,7 @@ export interface character{
|
||||
supaMemory?:boolean
|
||||
additionalAssets?:[string, string][]
|
||||
ttsReadOnlyQuoted?:boolean
|
||||
replaceGlobalNote:string
|
||||
}
|
||||
|
||||
|
||||
|
||||
34
src/ts/horde/getModels.ts
Normal file
34
src/ts/horde/getModels.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { sleep } from "../util"
|
||||
|
||||
let modelList:string[]|'loading' = null
|
||||
|
||||
//until horde is ready
|
||||
modelList = []
|
||||
|
||||
export async function getHordeModels():Promise<string[]> {
|
||||
|
||||
if(modelList === null){
|
||||
try {
|
||||
modelList = 'loading'
|
||||
const models = await fetch("https://stablehorde.net/api/v2/status/models?type=text")
|
||||
modelList = ((await models.json()).map((a) => {
|
||||
return a.name
|
||||
}) as string[])
|
||||
return modelList
|
||||
} catch (error) {
|
||||
modelList = null
|
||||
return []
|
||||
}
|
||||
}
|
||||
else if(modelList === 'loading'){
|
||||
while(true){
|
||||
if(modelList !== 'loading'){
|
||||
return getHordeModels()
|
||||
}
|
||||
await sleep(10)
|
||||
}
|
||||
}
|
||||
else{
|
||||
return modelList
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
||||
}
|
||||
|
||||
if(!currentChar.utilityBot){
|
||||
const mainp = currentChar.systemPrompt.length > 3 ? currentChar.systemPrompt : db.mainPrompt
|
||||
const mainp = currentChar.systemPrompt || db.mainPrompt
|
||||
|
||||
unformated.main.push({
|
||||
role: 'system',
|
||||
@@ -121,14 +121,14 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
||||
|
||||
unformated.globalNote.push({
|
||||
role: 'system',
|
||||
content: replacePlaceholders(db.globalNote, currentChar.name)
|
||||
content: replacePlaceholders(currentChar.replaceGlobalNote || db.globalNote, currentChar.name)
|
||||
})
|
||||
}
|
||||
|
||||
if(currentChat.note !== ''){
|
||||
unformated.authorNote.push({
|
||||
role: 'system',
|
||||
content: replacePlaceholders(currentChar.postHistoryInstructions, currentChat.note)
|
||||
content: replacePlaceholders(currentChat.note, currentChar.name)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import { pluginProcess } from "./plugins";
|
||||
import { language } from "../../lang";
|
||||
import { stringlizeChat, unstringlizeChat } from "./stringlize";
|
||||
import { globalFetch, isTauri } from "../globalApi";
|
||||
import { alertError } from "../alert";
|
||||
import { sleep } from "../util";
|
||||
|
||||
interface requestDataArgument{
|
||||
formated: OpenAIChat[]
|
||||
@@ -34,7 +36,7 @@ export async function requestChatData(arg:requestDataArgument, model:'model'|'su
|
||||
return da
|
||||
}
|
||||
trys += 1
|
||||
if(trys > db.requestRetrys){
|
||||
if(trys > db.requestRetrys || model.startsWith('horde')){
|
||||
return da
|
||||
}
|
||||
}
|
||||
@@ -411,7 +413,107 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model'
|
||||
}
|
||||
}
|
||||
}
|
||||
default:{
|
||||
default:{
|
||||
if(aiModel.startsWith("horde:::")){
|
||||
const realModel = aiModel.split(":::")[1].trim()
|
||||
|
||||
const workers = ((await (await fetch("https://stablehorde.net/api/v2/workers")).json()) as {id:string,models:string[]}[]).filter((a) => {
|
||||
|
||||
if(a && a.models && a.id){
|
||||
console.log(a)
|
||||
return a.models.includes(realModel)
|
||||
}
|
||||
return false
|
||||
}).map((a) => {
|
||||
return a.id
|
||||
})
|
||||
|
||||
const argument = {
|
||||
"prompt": "string",
|
||||
"params": {
|
||||
"n": 1,
|
||||
"frmtadsnsp": false,
|
||||
"frmtrmblln": false,
|
||||
"frmtrmspch": false,
|
||||
"frmttriminc": false,
|
||||
"max_context_length": 200,
|
||||
"max_length": 20,
|
||||
"rep_pen": 3,
|
||||
"rep_pen_range": 0,
|
||||
"rep_pen_slope": 10,
|
||||
"singleline": false,
|
||||
"temperature": db.temperature / 25,
|
||||
"tfs": 1,
|
||||
"top_a": 1,
|
||||
"top_k": 100,
|
||||
"top_p": 1,
|
||||
"typical": 1,
|
||||
"sampler_order": [
|
||||
0
|
||||
]
|
||||
},
|
||||
"trusted_workers": false,
|
||||
"slow_workers": true,
|
||||
"worker_blacklist": false,
|
||||
"dry_run": false
|
||||
}
|
||||
|
||||
const da = await fetch("https://stablehorde.net/api/v2/generate/text/async", {
|
||||
body: JSON.stringify(argument),
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"apikey": db.hordeConfig.apiKey
|
||||
}
|
||||
})
|
||||
|
||||
if(da.status !== 202){
|
||||
return {
|
||||
type: "fail",
|
||||
result: await da.text()
|
||||
}
|
||||
}
|
||||
|
||||
const json:{
|
||||
id:string,
|
||||
kudos:number,
|
||||
message:string
|
||||
} = await da.json()
|
||||
|
||||
let warnMessage = ""
|
||||
if(json.message && json.message.startsWith("Warning:")){
|
||||
warnMessage = "with " + json.message
|
||||
}
|
||||
|
||||
while(true){
|
||||
await sleep(1000)
|
||||
const data = await (await fetch("https://stablehorde.net/api/v2/generate/text/status/" + json.id)).json()
|
||||
if(!data.is_possible){
|
||||
fetch("https://stablehorde.net/api/v2/generate/text/status/" + json.id, {
|
||||
method: "DELETE"
|
||||
})
|
||||
return {
|
||||
type: 'fail',
|
||||
result: "Response not possible" + warnMessage
|
||||
}
|
||||
}
|
||||
if(data.done){
|
||||
const generations:{text:string}[] = data.generations
|
||||
if(generations && generations.length > 0){
|
||||
return {
|
||||
type: "success",
|
||||
result: generations[0].text
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'fail',
|
||||
result: "No Generations when done"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return {
|
||||
type: 'fail',
|
||||
result: (language.errors.unknownModel)
|
||||
|
||||
Reference in New Issue
Block a user