This commit is contained in:
2025-07-05 22:32:51 +09:00
parent 55a78b2a02
commit 574e04fa19
21 changed files with 556 additions and 541 deletions

View File

@@ -1,60 +1,82 @@
<script context="module" lang="ts">
import { getApiBase, getEndpointCompletions, getEndpointGenerations } from "../../ApiUtil.svelte";
import { countTokens } from "../../Models.svelte";
import { countMessageTokens } from "../../Stats.svelte";
import { globalStorage } from "../../Storage.svelte";
import type { Chat, Message, Model, ModelDetail } from "../../Types.svelte";
import { chatRequest, imageRequest } from "./request.svelte";
import { checkModel } from "./util.svelte";
import { encode } from "gpt-tokenizer";
import { get } from "svelte/store";
import chatModelsJson from './models.json';
import { getApiBase, getEndpointCompletions, getEndpointGenerations } from '../../ApiUtil.svelte'
import { countTokens } from '../../Models.svelte'
import { countMessageTokens } from '../../Stats.svelte'
import { globalStorage } from '../../Storage.svelte'
import type { Chat, Message, Model, ModelDetail } from '../../Types.svelte'
import { chatRequest, imageRequest } from './request.svelte'
import { checkModel } from './util.svelte'
// Lazy-load tokenizer to improve initial load time
let encode: any = null
// Simple token approximation for faster initial loads
const approximateTokens = (text: string): number[] => {
// Rough approximation: 1 token ≈ 4 characters for most text
return new Array(Math.ceil(text.length / 4)).fill(0)
}
const getTokenizer = async () => {
if (!encode) {
const tokenizer = await import('gpt-tokenizer')
encode = tokenizer.encode
}
return encode
}
import { get } from 'svelte/store'
import chatModelsJson from './models.json'
const hiddenSettings = {
startSequence: true,
stopSequence: true,
aggressiveStop: true,
delimiter: true,
userMessageStart: true,
userMessageEnd: true,
assistantMessageStart: true,
assistantMessageEnd: true,
systemMessageStart: true,
systemMessageEnd: true,
repetitionPenalty: true,
holdSocket: true,
// leadPrompt: true
} as any;
startSequence: true,
stopSequence: true,
aggressiveStop: true,
delimiter: true,
userMessageStart: true,
userMessageEnd: true,
assistantMessageStart: true,
assistantMessageEnd: true,
systemMessageStart: true,
systemMessageEnd: true,
repetitionPenalty: true,
holdSocket: true
// leadPrompt: true
} as any
const chatModelBase = {
type: "chat",
help: 'Below are the settings that OpenAI allows to be changed for the API calls. See the <a target="_blank" href="https://platform.openai.com/docs/api-reference/chat/create">OpenAI API docs</a> for more details.',
preFillMerge: (existingContent, newContent) => {
if (existingContent && !newContent.match(/^('(t|ll|ve|m|d|re)[^a-z]|\s|[.,;:(_-{}*^%$#@!?+=~`[\]])/i)) {
existingContent += " ";
}
return existingContent;
},
request: chatRequest,
check: checkModel,
getTokens: (value) => encode(value),
getEndpoint: (model) => get(globalStorage).openAICompletionEndpoint || getApiBase() + getEndpointCompletions(),
hideSetting: (chatId, setting) => !!hiddenSettings[setting.key],
countMessageTokens: (message: Message, model: Model, chat: Chat) => {
return countTokens(model, "## " + message.role + " ##:\r\n\r\n" + message.content + "\r\n\r\n\r\n");
},
countPromptTokens: (prompts: Message[], model: Model, chat: Chat): number => {
return (
prompts.reduce((a, m) => {
a += countMessageTokens(m, model, chat);
return a;
}, 0) + 3
);
},
} as ModelDetail;
type: 'chat',
help: 'Below are the settings that OpenAI allows to be changed for the API calls. See the <a target="_blank" href="https://platform.openai.com/docs/api-reference/chat/create">OpenAI API docs</a> for more details.',
preFillMerge: (existingContent, newContent) => {
if (existingContent && !newContent.match(/^('(t|ll|ve|m|d|re)[^a-z]|\s|[.,;:(_-{}*^%$#@!?+=~`[\]])/i)) {
existingContent += ' '
}
return existingContent
},
request: chatRequest,
check: checkModel,
getTokens: (value) => {
// Use approximation for faster initial loads, actual tokenizer loads async
if (!encode) {
getTokenizer() // Start loading tokenizer for future use
return approximateTokens(value)
}
return encode(value)
},
getEndpoint: (model) => get(globalStorage).openAICompletionEndpoint || getApiBase() + getEndpointCompletions(),
hideSetting: (chatId, setting) => !!hiddenSettings[setting.key],
countMessageTokens: (message: Message, model: Model, chat: Chat) => {
return countTokens(model, '## ' + message.role + ' ##:\r\n\r\n' + message.content + '\r\n\r\n\r\n')
},
countPromptTokens: (prompts: Message[], model: Model, chat: Chat): number => {
return (
prompts.reduce((a, m) => {
a += countMessageTokens(m, model, chat)
return a
}, 0) + 3
)
}
} as ModelDetail
export const chatModels: Record<string, ModelDetail> = {};
export const chatModels: Record<string, ModelDetail> = {}
for (const [key, { prompt, completion, max, reasoning, alias }] of Object.entries(chatModelsJson)) {
chatModels[key] = {
@@ -63,101 +85,101 @@
completion: completion / 1_000_000,
max,
...(reasoning ? { reasoning } : {}),
...(alias ? { alias } : {}),
};
...(alias ? { alias } : {})
}
}
const imageModelBase = {
type: "image",
prompt: 0.0,
max: 1000, // 1000 char prompt, max
request: imageRequest,
check: checkModel,
getTokens: (value) => [0],
getEndpoint: (model) => getApiBase() + getEndpointGenerations(),
hideSetting: (chatId, setting) => false,
} as ModelDetail;
type: 'image',
prompt: 0.0,
max: 1000, // 1000 char prompt, max
request: imageRequest,
check: checkModel,
getTokens: (value) => [0],
getEndpoint: (model) => getApiBase() + getEndpointGenerations(),
hideSetting: (chatId, setting) => false
} as ModelDetail
export const imageModels: Record<string, ModelDetail> = {
"dall-e-1024x1024": {
...imageModelBase,
completion: 0.02, // $0.020 per image
opt: {
size: "1024x1024",
},
},
"dall-e-512x512": {
...imageModelBase,
completion: 0.018, // $0.018 per image
opt: {
size: "512x512",
},
},
"dall-e-256x256": {
...imageModelBase,
type: "image",
completion: 0.016, // $0.016 per image
opt: {
size: "256x256",
},
},
"dall-e-3-1024x1024": {
...imageModelBase,
type: "image",
completion: 0.04, // $0.040 per image
opt: {
model: "dall-e-3",
size: "1024x1024",
},
},
"dall-e-3-1024x1792-Portrait": {
...imageModelBase,
type: "image",
completion: 0.08, // $0.080 per image
opt: {
model: "dall-e-3",
size: "1024x1792",
},
},
"dall-e-3-1792x1024-Landscape": {
...imageModelBase,
type: "image",
completion: 0.08, // $0.080 per image
opt: {
model: "dall-e-3",
size: "1792x1024",
},
},
"dall-e-3-1024x1024-HD": {
...imageModelBase,
type: "image",
completion: 0.08, // $0.080 per image
opt: {
model: "dall-e-3",
size: "1024x1024",
quality: "hd",
},
},
"dall-e-3-1024x1792-Portrait-HD": {
...imageModelBase,
type: "image",
completion: 0.12, // $0.080 per image
opt: {
model: "dall-e-3",
size: "1024x1792",
quality: "hd",
},
},
"dall-e-3-1792x1024-Landscape-HD": {
...imageModelBase,
type: "image",
completion: 0.12, // $0.080 per image
opt: {
model: "dall-e-3",
size: "1792x1024",
quality: "hd",
},
},
};
'dall-e-1024x1024': {
...imageModelBase,
completion: 0.02, // $0.020 per image
opt: {
size: '1024x1024'
}
},
'dall-e-512x512': {
...imageModelBase,
completion: 0.018, // $0.018 per image
opt: {
size: '512x512'
}
},
'dall-e-256x256': {
...imageModelBase,
type: 'image',
completion: 0.016, // $0.016 per image
opt: {
size: '256x256'
}
},
'dall-e-3-1024x1024': {
...imageModelBase,
type: 'image',
completion: 0.04, // $0.040 per image
opt: {
model: 'dall-e-3',
size: '1024x1024'
}
},
'dall-e-3-1024x1792-Portrait': {
...imageModelBase,
type: 'image',
completion: 0.08, // $0.080 per image
opt: {
model: 'dall-e-3',
size: '1024x1792'
}
},
'dall-e-3-1792x1024-Landscape': {
...imageModelBase,
type: 'image',
completion: 0.08, // $0.080 per image
opt: {
model: 'dall-e-3',
size: '1792x1024'
}
},
'dall-e-3-1024x1024-HD': {
...imageModelBase,
type: 'image',
completion: 0.08, // $0.080 per image
opt: {
model: 'dall-e-3',
size: '1024x1024',
quality: 'hd'
}
},
'dall-e-3-1024x1792-Portrait-HD': {
...imageModelBase,
type: 'image',
completion: 0.12, // $0.080 per image
opt: {
model: 'dall-e-3',
size: '1024x1792',
quality: 'hd'
}
},
'dall-e-3-1792x1024-Landscape-HD': {
...imageModelBase,
type: 'image',
completion: 0.12, // $0.080 per image
opt: {
model: 'dall-e-3',
size: '1792x1024',
quality: 'hd'
}
}
}
</script>