diff --git a/src/lang/en.ts b/src/lang/en.ts
index d7fb1ba3..5b47a1b2 100644
--- a/src/lang/en.ts
+++ b/src/lang/en.ts
@@ -1112,4 +1112,5 @@ export const languageEnglish = {
fallbackModel: "Fallback Model",
fallbackWhenBlankResponse: "Fallback When Blank Response",
doNotChangeFallbackModels: "Do Not Change Fallback Models on Preset Change",
+ customModels: "Custom Models",
}
diff --git a/src/lib/Setting/Pages/AdvancedSettings.svelte b/src/lib/Setting/Pages/AdvancedSettings.svelte
index ec9ed426..805cd9dc 100644
--- a/src/lib/Setting/Pages/AdvancedSettings.svelte
+++ b/src/lib/Setting/Pages/AdvancedSettings.svelte
@@ -14,6 +14,8 @@
import { Capacitor } from "@capacitor/core";
import { capStorageInvestigation } from "src/ts/storage/mobileStorage";
import Arcodion from "src/lib/UI/Arcodion.svelte";
+ import { PlusIcon, TrashIcon } from "lucide-svelte";
+ import { v4 } from "uuid";
let estaStorage:{
key:string,
@@ -254,6 +256,117 @@
{/each}
+{#snippet CustomFlagButton(index:number,name:string,flag:number)}
+
+{/snippet}
+
+
+
+ {#each DBState.db.customModels as model, index}
+
+ {language.name}
+
+ {language.proxyRequestModel}
+
+ URL
+
+ {language.tokenizer}
+ {
+ DBState.db.customModels[index].tokenizer = parseInt(e.currentTarget.value)
+ }}>
+ tiktokenCl100kBase
+ tiktokenO200Base
+ Mistral
+ Llama
+ NovelAI
+ Claude
+ NovelList
+ Llama3
+ Gemma
+ GoogleCloud
+ Cohere
+ DeepSeek
+
+ {language.format}
+ {
+ DBState.db.customModels[index].format = parseInt(e.currentTarget.value)
+ }}>
+ OpenAICompatible
+ OpenAILegacyInstruct
+ Anthropic
+ AnthropicLegacy
+ Mistral
+ GoogleCloud
+ VertexAIGemini
+ NovelList
+ Cohere
+ NovelAI
+ OobaLegacy
+ Ooba
+ Kobold
+ AWSBedrockClaude
+ OpenAIResponseAPI
+
+ {language.proxyAPIKey}
+
+ {language.additionalParams}
+
+
+ {@render CustomFlagButton(index,'hasImageInput', 0)}
+ {@render CustomFlagButton(index,'hasImageOutput', 1)}
+ {@render CustomFlagButton(index,'hasAudioInput', 2)}
+ {@render CustomFlagButton(index,'hasAudioOutput', 3)}
+ {@render CustomFlagButton(index,'hasPrefill', 4)}
+ {@render CustomFlagButton(index,'hasCache', 5)}
+ {@render CustomFlagButton(index,'hasFullSystemPrompt', 6)}
+ {@render CustomFlagButton(index,'hasFirstSystemPrompt', 7)}
+ {@render CustomFlagButton(index,'hasStreaming', 8)}
+ {@render CustomFlagButton(index,'requiresAlternateRole', 9)}
+ {@render CustomFlagButton(index,'mustStartWithUserInput', 10)}
+ {@render CustomFlagButton(index,'hasVideoInput', 12)}
+ {@render CustomFlagButton(index,'OAICompletionTokens', 13)}
+ {@render CustomFlagButton(index,'DeveloperRole', 14)}
+ {@render CustomFlagButton(index,'geminiThinking', 15)}
+ {@render CustomFlagButton(index,'geminiBlockOff', 16)}
+ {@render CustomFlagButton(index,'deepSeekPrefix', 17)}
+ {@render CustomFlagButton(index,'deepSeekThinkingInput', 18)}
+ {@render CustomFlagButton(index,'deepSeekThinkingOutput', 19)}
+
+
+ {/each}
+
+
+
+
+
+
{#if open}
-
+
{@render children?.()}
{/if}
diff --git a/src/lib/UI/ModelList.svelte b/src/lib/UI/ModelList.svelte
index 620549d2..99b01c32 100644
--- a/src/lib/UI/ModelList.svelte
+++ b/src/lib/UI/ModelList.svelte
@@ -74,6 +74,17 @@
{/await}
+ {#if DBState?.db.customModels?.length > 0}
+
+ {#each DBState.db.customModels as model}
+
+ {/each}
+
+
+ {/if}
+
+
+
{#if blankable}
{/if}
diff --git a/src/ts/model/modellist.ts b/src/ts/model/modellist.ts
index c75163c6..eb9e21fa 100644
--- a/src/ts/model/modellist.ts
+++ b/src/ts/model/modellist.ts
@@ -1450,6 +1450,24 @@ export function getModelInfo(id: string): LLMModel{
tokenizer: LLMTokenizer.Unknown
}
}
+ if(id.startsWith('xcustom:::')){
+ const customModels = db?.customModels || []
+ const found = customModels.find((model) => model.id === id)
+ if(found){
+ return {
+ id: found.id,
+ name: found.name,
+ shortName: found.name,
+ fullName: found.name,
+ internalID: found.internalId,
+ provider: LLMProvider.AsIs,
+ format: found.format,
+ flags: found.flags,
+ parameters: ['temperature', 'top_p', 'frequency_penalty', 'presence_penalty', 'repetition_penalty', 'min_p', 'top_a', 'top_k', 'thinking_tokens'],
+ tokenizer: found.tokenizer
+ }
+ }
+ }
return {
id,
diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts
index 1ca1eaec..8502f2d9 100644
--- a/src/ts/process/request.ts
+++ b/src/ts/process/request.ts
@@ -55,6 +55,7 @@ interface RequestDataArgumentExtended extends requestDataArgument{
modelInfo?:LLMModel
customURL?:string
mode?:ModelModeExtended
+ key?:string
}
type requestDataResponse = {
@@ -515,6 +516,11 @@ export async function requestChatDataMain(arg:requestDataArgument, model:ModelMo
targ.modelInfo.format = db.customAPIFormat
targ.customURL = db.forceReplaceUrl
}
+ if(targ.aiModel.startsWith('xcustom:::')){
+ const found = db.customModels.find(m => m.id === targ.aiModel)
+ targ.customURL = found?.url
+ targ.key = found?.key
+ }
if(db.seperateModelsForAxModels && !arg.staticModel){
if(db.seperateModels[model]){
@@ -775,7 +781,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise
v !== ''),
otherAx: data.fallbackModels.otherAx.filter((v) => v !== '')
}
+ data.customModels ??= []
changeLanguage(data.language)
setDatabaseLite(data)
}
@@ -968,6 +969,17 @@ export interface Database{
}
doNotChangeFallbackModels: boolean
fallbackWhenBlankResponse: boolean
+ customModels: {
+ id: string
+ internalId: string
+ url: string
+ format: LLMFormat
+ tokenizer: LLMTokenizer
+ key: string
+ name: string
+ params: string
+ flags: LLMFlags[]
+ }[]
}
interface SeparateParameters{
@@ -1784,7 +1796,7 @@ import type { RisuModule } from '../process/modules';
import type { SerializableHypaV2Data } from '../process/memory/hypav2';
import { decodeRPack, encodeRPack } from '../rpack/rpack_bg';
import { DBState, selectedCharID } from '../stores.svelte';
-import { LLMFlags, LLMFormat } from '../model/modellist';
+import { LLMFlags, LLMFormat, LLMTokenizer } from '../model/modellist';
import type { Parameter } from '../process/request';
import type { HypaModel } from '../process/memory/hypamemory';
import type { SerializableHypaV3Data } from '../process/memory/hypav3';