Skip to content

Commit

Permalink
Merge pull request #494 from stadtwerk/main
Browse files Browse the repository at this point in the history
Allow alternative OpenAI-compatible endpoints
  • Loading branch information
Niek authored Oct 4, 2024
2 parents 7aff5db + 5f25f90 commit ceca482
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 160 deletions.
2 changes: 0 additions & 2 deletions src/lib/ApiUtil.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<script context="module" lang="ts">
// This makes it possible to override the OpenAI API base URL in the .env file
const apiBase = import.meta.env.VITE_API_BASE || 'https://api.openai.com'
const endpointCompletions = import.meta.env.VITE_ENDPOINT_COMPLETIONS || '/v1/chat/completions'
const endpointGenerations = import.meta.env.VITE_ENDPOINT_GENERATIONS || '/v1/images/generations'
const endpointModels = import.meta.env.VITE_ENDPOINT_MODELS || '/v1/models'
const endpointEmbeddings = import.meta.env.VITE_ENDPOINT_EMBEDDINGS || '/v1/embeddings'
const petalsBase = import.meta.env.VITE_PEDALS_WEBSOCKET || 'wss://chat.petals.dev'
const endpointPetals = import.meta.env.VITE_PEDALS_WEBSOCKET || '/api/v2/generate'
export const getApiBase = ():string => apiBase
export const getEndpointCompletions = ():string => endpointCompletions
export const getEndpointGenerations = ():string => endpointGenerations
export const getEndpointModels = ():string => endpointModels
Expand Down
10 changes: 5 additions & 5 deletions src/lib/Chat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
let showSettingsModal
let scDelay
const onStateChange = (...args:any) => {
const onStateChange = async (...args:any) => {
if (!chat) return
clearTimeout(scDelay)
setTimeout(() => {
setTimeout(async () => {
if (chat.startSession) {
restartProfile(chatId)
await restartProfile(chatId)
if (chat.startSession) {
chat.startSession = false
saveChatStore()
Expand Down Expand Up @@ -112,7 +112,7 @@
setCurrentChat(chatId)
chatRequest = new ChatRequest()
chatRequest.setChat(chat)
await chatRequest.setChat(chat)
chat.lastAccess = Date.now()
saveChatStore()
Expand Down Expand Up @@ -148,7 +148,7 @@
console.log('Speech recognition not supported')
}
if (chat.startSession) {
restartProfile(chatId)
await restartProfile(chatId)
if (chat.startSession) {
chat.startSession = false
saveChatStore()
Expand Down
20 changes: 10 additions & 10 deletions src/lib/ChatOptionMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@
showChatMenu = false
}
const restartChatSession = () => {
const restartChatSession = async () => {
close()
restartProfile(chatId)
await restartProfile(chatId)
$checkStateChange++ // signal chat page to start profile
}
Expand All @@ -125,17 +125,17 @@
})
}
const importProfileFromFile = (e) => {
const importProfileFromFile = async (e) => {
const image = e.target.files[0]
e.target.value = null
const reader = new FileReader()
reader.onload = e => {
reader.onload = async (e) => {
const json = (e.target || {}).result as string
try {
const profile = JSON.parse(json) as ChatSettings
profile.profileName = newNameForProfile(profile.profileName || '')
profile.profileName = await newNameForProfile(profile.profileName || '')
profile.profile = null as any
saveCustomProfile(profile)
await saveCustomProfile(profile)
openModal(PromptConfirm, {
title: 'Profile Restored',
class: 'is-info',
Expand Down Expand Up @@ -174,17 +174,17 @@
<span class="menu-icon"><Fa icon={faGear}/></span> Chat Profile Settings
</a>
<hr class="dropdown-divider">
<a href={'#'} class:is-disabled={!hasActiveModels()} on:click|preventDefault={() => { hasActiveModels() && close(); hasActiveModels() && startNewChatWithWarning(chatId) }} class="dropdown-item">
<a href={'#'} class:is-disabled={!hasActiveModels()} on:click|preventDefault={async () => { hasActiveModels() && close(); hasActiveModels() && await startNewChatWithWarning(chatId) }} class="dropdown-item">
<span class="menu-icon"><Fa icon={faSquarePlus}/></span> New Chat from Default
</a>
<a href={'#'} class:is-disabled={!chatId} on:click|preventDefault={() => { chatId && close(); chatId && startNewChatFromChatId(chatId) }} class="dropdown-item">
<a href={'#'} class:is-disabled={!chatId} on:click|preventDefault={async () => { chatId && close(); chatId && await startNewChatFromChatId(chatId) }} class="dropdown-item">
<span class="menu-icon"><Fa icon={faSquarePlusOutline}/></span> New Chat from Current
</a>
<a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) close(); copyChat(chatId) }}>
<span class="menu-icon"><Fa icon={faClone}/></span> Clone Chat
</a>
<hr class="dropdown-divider">
<a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) restartChatSession() }}>
<a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={async () => { if (chatId) await restartChatSession() }}>
<span class="menu-icon"><Fa icon={faRotateRight}/></span> Restart Chat Session
</a>
<a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) close(); clearMessages(chatId) }}>
Expand Down Expand Up @@ -231,4 +231,4 @@
</div>

<input style="display:none" type="file" accept=".json" on:change={(e) => importChatFromFile(e)} bind:this={chatFileInput} >
<input style="display:none" type="file" accept=".json" on:change={(e) => importProfileFromFile(e)} bind:this={profileFileInput} >
<input style="display:none" type="file" accept=".json" on:change={async (e) => await importProfileFromFile(e)} bind:this={profileFileInput} >
27 changes: 14 additions & 13 deletions src/lib/ChatRequest.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export class ChatRequest {
controller:AbortController
providerData: Record<string, any> = {}
setChat (chat: Chat) {
async setChat (chat: Chat) {
this.chat = chat
this.chat.settings.model = this.getModel()
this.chat.settings.model = await this.getModel()
}
getChat (): Chat {
Expand Down Expand Up @@ -63,7 +63,7 @@ export class ChatRequest {
// TODO: Continue to break this method down to smaller chunks
const _this = this
const chat = getChat(_this.chat.id)
this.setChat(chat)
await this.setChat(chat)
const chatSettings = _this.chat.settings
const chatId = chat.id
const imagePromptDetect = /^\s*(please|can\s+you|will\s+you)*\s*(give|generate|create|show|build|design)\s+(me)*\s*(an|a|set|a\s+set\s+of)*\s*([0-9]+|one|two|three|four)*\s+(image|photo|picture|pic)s*\s*(for\s+me)*\s*(of|[^a-z0-9]+|about|that\s+has|showing|with|having|depicting)\s+[^a-z0-9]*(.*)$/i
Expand Down Expand Up @@ -100,7 +100,7 @@ export class ChatRequest {
}
}
const model = this.getModel()
const model = await this.getModel()
const modelDetail = getModelDetail(model)
const maxTokens = getModelMaxTokens(model)
Expand All @@ -117,7 +117,7 @@ export class ChatRequest {
// Inject hidden prompts if requested
// if (!opts.summaryRequest)
this.buildHiddenPromptPrefixMessages(filtered, true)
await this.buildHiddenPromptPrefixMessages(filtered, true)
const messagePayload = filtered
.filter(m => { if (m.skipOnce) { delete m.skipOnce; return false } return true })
.map(m => {
Expand Down Expand Up @@ -231,11 +231,11 @@ export class ChatRequest {
return chatResponse
}
getModel (): Model {
return this.chat.settings.model || getDefaultModel()
async getModel (): Promise<Model> {
return this.chat.settings.model || await getDefaultModel()
}
private buildHiddenPromptPrefixMessages (messages: Message[], insert:boolean = false): Message[] {
private async buildHiddenPromptPrefixMessages (messages: Message[], insert:boolean = false): Promise<Message[]> {
const chat = this.chat
const chatSettings = chat.settings
const hiddenPromptPrefix = mergeProfileFields(chatSettings, chatSettings.hiddenPromptPrefix).trim()
Expand Down Expand Up @@ -271,7 +271,7 @@ export class ChatRequest {
}
if (injectedPrompt) messages.pop()
}
const model = this.getModel()
const model = await this.getModel()
const messageDetail = getModelDetail(model)
if (getLeadPrompt(this.getChat()).trim() && messageDetail.type === 'chat') {
const lastMessage = (results.length && injectedPrompt && !isContinue) ? results[results.length - 1] : messages[messages.length - 1]
Expand All @@ -291,11 +291,12 @@ export class ChatRequest {
* Gets an estimate of how many extra tokens will be added that won't be part of the visible messages
* @param filtered
*/
private getTokenCountPadding (filtered: Message[], chat: Chat): number {
private async getTokenCountPadding (filtered: Message[], chat: Chat): Promise<number> {
const model = await this.getModel()
let result = 0
// add cost of hiddenPromptPrefix
result += this.buildHiddenPromptPrefixMessages(filtered)
.reduce((a, m) => a + countMessageTokens(m, this.getModel(), chat), 0)
result += (await this.buildHiddenPromptPrefixMessages(filtered))
.reduce((a, m) => a + countMessageTokens(m, model, chat), 0)
// more here eventually?
return result
}
Expand All @@ -306,7 +307,7 @@ export class ChatRequest {
const chatSettings = chat.settings
const chatId = chat.id
const reductionMode = chatSettings.continuousChat
const model = _this.getModel()
const model = await _this.getModel()
const maxTokens = getModelMaxTokens(model) // max tokens for model
const continueRequest = async () => {
Expand Down
52 changes: 27 additions & 25 deletions src/lib/ChatSettingsModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
let showSettingsModal = 0
let showProfileMenu:boolean = false
let profileFileInput
let defaultProfile = getDefaultProfileKey()
let defaultProfile
let isDefault = false
const settingsList = getChatSettingList()
Expand All @@ -63,6 +63,8 @@
onMount(async () => {
originalProfile = chatSettings && chatSettings.profile
originalSettings = chatSettings && JSON.parse(JSON.stringify(chatSettings))
defaultProfile = await getDefaultProfileKey()
})
afterUpdate(() => {
Expand Down Expand Up @@ -112,17 +114,17 @@
return profileUri
}
const cloneProfile = () => {
const cloneProfile = async () => {
showProfileMenu = false
const clone = JSON.parse(JSON.stringify(chat.settings))
const name = chat.settings.profileName
clone.profileName = newNameForProfile(name || '')
clone.profileName = await newNameForProfile(name || '')
clone.profile = null
try {
saveCustomProfile(clone)
await saveCustomProfile(clone)
chat.settings.profile = clone.profile
chat.settings.profileName = clone.profileName
applyProfile(chatId, clone.profile)
await applyProfile(chatId, clone.profile)
refreshSettings()
} catch (e) {
errorNotice('Error cloning profile:', e)
Expand All @@ -140,14 +142,14 @@
})
}
const deleteProfile = () => {
const deleteProfile = async () => {
showProfileMenu = false
try {
deleteCustomProfile(chatId, chat.settings.profile)
await deleteCustomProfile(chatId, chat.settings.profile)
chat.settings.profile = globalStore.defaultProfile || ''
saveChatStore()
setGlobalSettingValueByKey('lastProfile', chat.settings.profile)
applyProfile(chatId, chat.settings.profile)
await applyProfile(chatId, chat.settings.profile)
refreshSettings()
} catch (e) {
console.error(e)
Expand All @@ -161,42 +163,42 @@
refreshSettings()
}
const importProfileFromFile = (e) => {
const importProfileFromFile = async (e) => {
const image = e.target.files[0]
e.target.value = null
const reader = new FileReader()
reader.readAsText(image)
reader.onload = e => {
reader.onload = async (e) => {
const json = (e.target || {}).result as string
try {
const profile = JSON.parse(json)
profile.profileName = newNameForProfile(profile.profileName || '')
profile.profileName = await newNameForProfile(profile.profileName || '')
profile.profile = null
saveCustomProfile(profile)
await saveCustomProfile(profile)
refreshSettings()
} catch (e) {
errorNotice('Unable to import profile:', e)
}
}
}
const updateProfileSelectOptions = () => {
const updateProfileSelectOptions = async () => {
const profileSelect = getChatSettingObjectByKey('profile') as ChatSetting & SettingSelect
profileSelect.options = getProfileSelect()
chatDefaults.profile = getDefaultProfileKey()
profileSelect.options = await getProfileSelect()
chatDefaults.profile = await getDefaultProfileKey()
chatDefaults.max_tokens = getModelMaxTokens(chatSettings.model)
// const defaultProfile = globalStore.defaultProfile || profileSelect.options[0].value
defaultProfile = getDefaultProfileKey()
defaultProfile = await getDefaultProfileKey()
isDefault = defaultProfile === chatSettings.profile
}
const showSettings = async () => {
setDirty()
await setDirty()
// Show settings modal
showSettingsModal++
// Get profile options
updateProfileSelectOptions()
await updateProfileSelectOptions()
// Refresh settings modal
showSettingsModal++
Expand All @@ -215,20 +217,20 @@
setTimeout(() => sizeTextElements(profileChanged))
}
const saveProfile = () => {
const saveProfile = async () => {
showProfileMenu = false
try {
saveCustomProfile(chat.settings)
await saveCustomProfile(chat.settings)
refreshSettings()
} catch (e) {
errorNotice('Error saving profile:', e)
}
}
const startNewChat = () => {
const startNewChat = async () => {
const differentProfile = originalSettings.profile !== chatSettings.profile
// start new
const newChatId = addChat(chatSettings)
const newChatId = await addChat(chatSettings)
// restore original
if (differentProfile) {
chat.settings = originalSettings
Expand All @@ -247,13 +249,13 @@
: (x === y || ((x === undefined || x === null || x === false) && (y === undefined || y === null || y === false)))
}
const setDirty = (e:CustomEvent|undefined = undefined) => {
const setDirty = async (e:CustomEvent|undefined = undefined) => {
if (e) {
const setting = e.detail as ChatSetting
const key = setting.key
if (key === 'profile') return
}
const profile = getProfile(chatSettings.profile)
const profile = await getProfile(chatSettings.profile)
chatSettings.isDirty = !deepEqual(profile, chatSettings)
}
Expand Down Expand Up @@ -343,4 +345,4 @@
</div>
</div>

<input style="display:none" type="file" accept=".json" on:change={(e) => importProfileFromFile(e)} bind:this={profileFileInput} >
<input style="display:none" type="file" accept=".json" on:change={async (e) => await importProfileFromFile(e)} bind:this={profileFileInput} >
Loading

0 comments on commit ceca482

Please sign in to comment.