diff --git a/package-lock.json b/package-lock.json
index 2f715e4..e93028b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
"bulma": "^0.9.4",
"bulma-prefers-dark": "^0.1.0-beta.1",
"copy-to-clipboard": "^3.3.3",
+ "dexie": "^4.0.1-alpha.20",
"eslint-config-standard-with-typescript": "^35.0.0",
"eslint-plugin-svelte3": "^4.0.0",
"flourite": "^1.2.3",
@@ -1601,6 +1602,12 @@
"node": ">=8"
}
},
+ "node_modules/dexie": {
+ "version": "4.0.1-alpha.20",
+ "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.1-alpha.20.tgz",
+ "integrity": "sha512-q/nMsCQiTWTmnw11aseJLfAsGQ/9t05sjWltgw1/r2TbfnIkmfjdTt8ATSIwmtKXuSznEZ5czazvL5LO5rR+6w==",
+ "dev": true
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
diff --git a/package.json b/package.json
index b08903e..2eba101 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"bulma": "^0.9.4",
"bulma-prefers-dark": "^0.1.0-beta.1",
"copy-to-clipboard": "^3.3.3",
+ "dexie": "^4.0.1-alpha.20",
"eslint-config-standard-with-typescript": "^35.0.0",
"eslint-plugin-svelte3": "^4.0.0",
"flourite": "^1.2.3",
diff --git a/src/app.scss b/src/app.scss
index c7d2a98..da7f917 100644
--- a/src/app.scss
+++ b/src/app.scss
@@ -245,8 +245,6 @@ $modal-background-background-color-dark: rgba($dark, 0.86) !default; // remove t
}
}
-
-
/* Loading chat messages */
.is-loading {
opacity: 0.5;
@@ -462,6 +460,10 @@ aside.menu.main-menu .menu-expanse {
.control.send .button {
width: 60px;
}
+ textarea {
+ max-height: calc(100vh - (var(--chatContentPaddingBottom) + var(--runningTotalLineHeight) * var(--running-totals))) !important;
+ min-height: 38px !important;
+ }
}
@media only screen and (max-width: 768px) {
diff --git a/src/lib/ApiUtil.svelte b/src/lib/ApiUtil.svelte
index 7beff67..01b41ff 100644
--- a/src/lib/ApiUtil.svelte
+++ b/src/lib/ApiUtil.svelte
@@ -2,9 +2,11 @@
// 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'
export const getApiBase = ():string => apiBase
export const getEndpointCompletions = ():string => endpointCompletions
+ export const getEndpointGenerations = ():string => endpointGenerations
export const getEndpointModels = ():string => endpointModels
\ No newline at end of file
diff --git a/src/lib/ChatCompletionResponse.svelte b/src/lib/ChatCompletionResponse.svelte
index e2afb6d..986784a 100644
--- a/src/lib/ChatCompletionResponse.svelte
+++ b/src/lib/ChatCompletionResponse.svelte
@@ -1,7 +1,8 @@
+ {#if imageUrl}
+
+ {/if}
{:else}
+ {#if imageUrl}
+
+ {/if}
{/if}
{#if isSystem}
@@ -261,7 +286,7 @@
{
checkDelete()
}}
@@ -273,11 +298,11 @@
{/if}
{/if}
- {#if !message.summarized && !isError}
+ {#if !isImage && !message.summarized && !isError}
{
checkTruncate()
}}
@@ -289,11 +314,11 @@
{/if}
{/if}
- {#if !message.summarized && !isSystem && !isError}
+ {#if !isImage && !message.summarized && !isSystem && !isError}
{
setSuppress(!message.suppress)
}}
@@ -305,6 +330,18 @@
{/if}
{/if}
+ {#if imageUrl}
+ {
+ downloadImage()
+ }}
+ >
+
+
+ {/if}
diff --git a/src/lib/Export.svelte b/src/lib/Export.svelte
index 7050fd2..e7fa582 100644
--- a/src/lib/Export.svelte
+++ b/src/lib/Export.svelte
@@ -1,8 +1,9 @@
\ No newline at end of file
diff --git a/src/lib/Models.svelte b/src/lib/Models.svelte
index 54ada48..a3953c8 100644
--- a/src/lib/Models.svelte
+++ b/src/lib/Models.svelte
@@ -14,10 +14,38 @@ const modelDetails : Record = {
completion: 0.00006, // $0.06 per 1000 tokens completion
max: 8192 // 8k max token buffer
},
+ 'gpt-3.5-turbo-0613': {
+ prompt: 0.0000015, // $0.0015 per 1000 tokens prompt
+ completion: 0.0000015, // $0.0015 per 1000 tokens completion
+ max: 4096 // 4k max token buffer
+ },
'gpt-3.5': {
prompt: 0.000002, // $0.002 per 1000 tokens prompt
completion: 0.000002, // $0.002 per 1000 tokens completion
max: 4096 // 4k max token buffer
+ },
+ 'gpt-3.5-turbo-16k': {
+ prompt: 0.000003, // $0.003 per 1000 tokens prompt
+ completion: 0.000004, // $0.004 per 1000 tokens completion
+ max: 16384 // 16k max token buffer
+ }
+}
+
+const imageModels : Record = {
+ 'dall-e-1024x1024': {
+ prompt: 0.00,
+ completion: 0.020, // $0.020 per image
+ max: 1000 // 1000 char prompt, max
+ },
+ 'dall-e-512x512': {
+ prompt: 0.00,
+ completion: 0.018, // $0.018 per image
+ max: 1000 // 1000 char prompt, max
+ },
+ 'dall-e-256x256': {
+ prompt: 0.00,
+ completion: 0.016, // $0.016 per image
+ max: 1000 // 1000 char prompt, max
}
}
@@ -35,15 +63,18 @@ export const supportedModels : Record = {
'gpt-4-32k': modelDetails['gpt-4-32k'],
'gpt-4-32k-0314': modelDetails['gpt-4-32k'],
'gpt-3.5-turbo': modelDetails['gpt-3.5'],
- 'gpt-3.5-turbo-0301': modelDetails['gpt-3.5']
+ 'gpt-3.5-turbo-16k': modelDetails['gpt-3.5-turbo-16k'],
+ 'gpt-3.5-turbo-0301': modelDetails['gpt-3.5'],
+ 'gpt-3.5-turbo-0613': modelDetails['gpt-3.5-turbo-0613']
}
const lookupList = {
+ ...imageModels,
...modelDetails,
...supportedModels
}
-export const supportedModelKeys = Object.keys(supportedModels)
+export const supportedModelKeys = Object.keys({ ...supportedModels, ...imageModels })
const tpCache : Record = {}
diff --git a/src/lib/Settings.svelte b/src/lib/Settings.svelte
index b3dc4b9..d732417 100644
--- a/src/lib/Settings.svelte
+++ b/src/lib/Settings.svelte
@@ -86,6 +86,7 @@ const defaults:ChatSettings = {
autoStartSession: false,
trainingPrompts: [],
hiddenPromptPrefix: '',
+ imageGenerationSize: '',
// useResponseAlteration: false,
// responseAlterations: [],
isDirty: false
@@ -97,6 +98,12 @@ const excludeFromProfile = {
isDirty: true
}
+export const imageGenerationSizes = [
+ '1024x1024', '512x512', '256x256'
+]
+
+export const imageGenerationSizeTypes = ['', ...imageGenerationSizes]
+
const profileSetting: ChatSetting & SettingSelect = {
key: 'profile',
name: 'Profile',
@@ -269,6 +276,18 @@ const summarySettings: ChatSetting[] = [
placeholder: 'Enter a prompt that will be used to summarize past prompts here.',
type: 'textarea',
hide: (chatId) => getChatSettings(chatId).continuousChat !== 'summary'
+ },
+ {
+ key: 'imageGenerationSize',
+ name: 'Image Generation Size',
+ header: 'Image Generation',
+ headerClass: 'is-info',
+ title: 'Prompt an image with: show me an image of ...',
+ type: 'select',
+ options: [
+ { value: '', text: 'OFF - Disable Image Generation' },
+ ...imageGenerationSizes.map(s => { return { value: s, text: s } })
+ ]
}
]
diff --git a/src/lib/Storage.svelte b/src/lib/Storage.svelte
index 80eafe0..967eca0 100644
--- a/src/lib/Storage.svelte
+++ b/src/lib/Storage.svelte
@@ -6,7 +6,10 @@
import { v4 as uuidv4 } from 'uuid'
import { getProfile, getProfiles, isStaticProfile, newNameForProfile, restartProfile } from './Profiles.svelte'
import { errorNotice } from './Util.svelte'
+ import { deleteImage, setImage } from './ImageStore.svelte'
+ // TODO: move chatsStorage to indexedDB with localStorage as a fallback for private browsing.
+ // Enough long chats will overflow localStorage.
export const chatsStorage = persisted('chats', [] as Chat[])
export const latestModelMap = persisted('latestModelMap', {} as Record) // What was returned when a model was requested
export const globalStorage = persisted('global', {} as GlobalSettings)
@@ -53,7 +56,7 @@
return chatId
}
- export const addChatFromJSON = (json: string): number => {
+ export const addChatFromJSON = async (json: string): Promise => {
const chats = get(chatsStorage)
// Find the max chatId
@@ -73,6 +76,10 @@
chat.id = chatId
+ // Make sure images are moved to indexedDB store,
+ // else they would clobber local storage
+ await updateChatImages(chatId, chat)
+
// Add a new chat
chats.push(chat)
chatsStorage.set(chats)
@@ -154,7 +161,10 @@
}
export const clearChats = () => {
- chatsStorage.set([])
+ const chats = get(chatsStorage)
+ chats.forEach(c => deleteChat(c.id)) // make sure images are removed
+ // TODO: add a clear images option to make this faster
+ // chatsStorage.set([])
}
export const saveChatStore = () => {
const chats = get(chatsStorage)
@@ -268,13 +278,16 @@
const chat = chats.find((chat) => chat.id === chatId) as Chat
const index = chat.messages.findIndex((m) => m.uuid === uuid)
const message = getMessage(chat, uuid)
- if (message && message.summarized) throw new Error('Unable to delete summarized message')
- if (message && message.summary) throw new Error('Unable to directly delete message summary')
+ if (message?.summarized) throw new Error('Unable to delete summarized message')
+ if (message?.summary) throw new Error('Unable to directly delete message summary')
// const found = chat.messages.filter((m) => m.uuid === uuid)
if (index < 0) {
console.error(`Unable to find and delete message with ID: ${uuid}`)
return
}
+ if (message?.image) {
+ deleteImage(chatId, message.image.id)
+ }
// console.warn(`Deleting message with ID: ${uuid}`, found, index)
chat.messages.splice(index, 1) // remove item
chatsStorage.set(chats)
@@ -303,10 +316,21 @@
export const deleteChat = (chatId: number) => {
const chats = get(chatsStorage)
+ const chat = getChat(chatId)
+ chat?.messages?.forEach(m => {
+ if (m.image) deleteImage(chatId, m.image.id)
+ })
chatsStorage.set(chats.filter((chat) => chat.id !== chatId))
}
- export const copyChat = (chatId: number) => {
+ export const updateChatImages = async (chatId: number, chat: Chat) => {
+ for (let i = 0; i < chat.messages.length; i++) {
+ const m = chat.messages[i]
+ if (m.image) m.image = await setImage(chatId, m.image)
+ }
+ }
+
+ export const copyChat = async (chatId: number) => {
const chats = get(chatsStorage)
const chat = chats.find((chat) => chat.id === chatId) as Chat
const nameMap = chats.reduce((a, chat) => { a[chat.name] = chat; return a }, {})
@@ -323,6 +347,8 @@
// Set new name
chatCopy.name = cname
+ await updateChatImages(chatId, chatCopy)
+
// Add a new chat
chats.push(chatCopy)
diff --git a/src/lib/Types.svelte b/src/lib/Types.svelte
index 246eedf..f944556 100644
--- a/src/lib/Types.svelte
+++ b/src/lib/Types.svelte
@@ -1,8 +1,11 @@