diff --git a/README.md b/README.md index 0cf66fa..26f15d3 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ To use Internet search you need a [Tavily API key](https://app.tavily.com/home). ## DONE +- [x] DALL-E as tool - [x] Google Gemini API - [x] Prompt anywhere - [x] Cancel commands diff --git a/css/panel.css b/css/panel.css index 2eaf639..0c1e61f 100644 --- a/css/panel.css +++ b/css/panel.css @@ -4,7 +4,7 @@ font-size: 10pt; padding-left: 32px; padding-right: 32px; - margin-bottom: 24px; + margin-bottom: 16px; } .settings form .group label { diff --git a/css/themes/base.css b/css/themes/base.css index b4f567d..84bf477 100644 --- a/css/themes/base.css +++ b/css/themes/base.css @@ -4,6 +4,10 @@ margin-bottom: 32px; } +.message .image-container { + margin-bottom: 12px; +} + .message .body, .message .actions { margin: 0px 32px; } @@ -108,4 +112,9 @@ .message .image-container:hover .download { display: block; -} \ No newline at end of file +} + +.message.assistant .actions { + position: relative; + top: -16px; +} diff --git a/css/themes/openai.css b/css/themes/openai.css index 0dec406..b5183cd 100644 --- a/css/themes/openai.css +++ b/css/themes/openai.css @@ -43,13 +43,7 @@ border-radius: 8px; } -.messages.openai .message.text .actions { +.messages.openai .message .actions { position: relative; top: -16px; } - -.messages.openai .message.image .actions { - position: relative; - top: -4px; -} - diff --git a/defaults/settings.json b/defaults/settings.json index ad3f44a..88ee697 100644 --- a/defaults/settings.json +++ b/defaults/settings.json @@ -11,7 +11,6 @@ }, "instructions": { "default": "You are a helpful assistant. You are here to help the user with any questions they have.", - "routing": "Your role is to determine if the following request is a text or an image generation request. You just reply TEXT or IMAGE.", "titling": "You are an assistant whose task is to find the best title for the conversation below. The title should be just a few words.", "titling_user": "Provide a title for the conversation above. Do not return anything other than the title. Do not wrap responses in quotes." }, @@ -106,6 +105,9 @@ "plugins": { "browse": {}, "python": {}, - "tavily": {} + "tavily": {}, + "dalle": { + "enabled": true + } } } diff --git a/src/App.vue b/src/App.vue index a5490fc..6075937 100644 --- a/src/App.vue +++ b/src/App.vue @@ -17,14 +17,12 @@ onMounted(() => { let platform = { 'win32': 'windows', 'darwin': 'macos', - }[window.api.platform]||'' + }[window.api.platform]||'generic' // add it everywhere - if (platform) { - window.platform = platform - document.platform = platform - document.querySelector('body').classList.add(platform) - } + window.platform = platform + document.platform = platform + document.querySelector('body').classList.add(platform) }) diff --git a/src/components/MessageItem.vue b/src/components/MessageItem.vue index 0dfe703..23c9ff8 100644 --- a/src/components/MessageItem.vue +++ b/src/components/MessageItem.vue @@ -9,18 +9,15 @@
- +
- -
- - -
+ + -
-
+
+
@@ -30,24 +27,7 @@
-
-
- {{ copyLabel }} -
-
- Stop - Cancel - Read -
-
- Edit -
-
-
- - -
+ @@ -55,7 +35,9 @@ import { ref, computed, onMounted, onUnmounted } from 'vue' import { store } from '../services/store' -import useAudioPlayer from '../composables/audio' +import MessageItemBody from './MessageItemBody.vue' +import MessageItemImage from './MessageItemImage.vue' +import MessageItemActions from './MessageItemActions.vue' import Chat from '../models/chat' import Message from '../models/message' import Loader from './Loader.vue' @@ -73,12 +55,7 @@ const props = defineProps({ const emits = defineEmits(['image-loaded']) const hovered = ref(false) -const fullScreenImageUrl = ref(null) const copyLabel = ref('Copy') -const audioState = ref({ - state: 'idle', - messageId: null, -}) // onUpdated is not called for an unknown reason // so let's hack it @@ -89,23 +66,18 @@ onMounted(() => { link.target = "_blank" }) }, 599) - useAudioPlayer().addListener(onAudioPlayerStatus) }) onUnmounted(() => { clearInterval(updateLinkInterval) - useAudioPlayer().removeListener(onAudioPlayerStatus) }) -const mgsAudioState = (message) => { - return message.uuid == audioState.value.messageId ? audioState.value.state : 'idle' -} - const authorName = computed(() => { return props.message.role === 'assistant' ? 'Assistant' : 'You' }) const imageUrl = computed(() => { + if (props.message.type !== 'image' || typeof props.message.content !== 'string') { return null } else if (props.message.content.startsWith('http')) { @@ -116,6 +88,7 @@ const imageUrl = computed(() => { } else { return 'data:image/png;base64,' + props.message.content } + }) // using simple css :hover @@ -125,57 +98,12 @@ const onHover = (value) => { hovered.value = value } -const onImageLoaded = (message) => { - emits('image-loaded', message) -} - -const onCopy = (message) => { - if (message.type == 'text') { - window.api.clipboard.writeText(message.content) - } else if (message.type == 'image') { - window.api.clipboard.writeImage(message.content) - } - copyLabel.value = 'Copied!' - setTimeout(() => copyLabel.value = 'Copy', 1000) -} - -const onAudioPlayerStatus = (status) => { - audioState.value = { state: status.state, messageId: status.uuid } -} - -const onToggleRead = async (message) => { - await useAudioPlayer().play(document.querySelector('.read audio'),message.uuid, message.content) -} - -const onEdit = (message) => { - emitEvent('set-prompt', message) -} - -const onFullscreen = (url) => { - fullScreenImageUrl.value = url - window.api.fullscreen(true) +const onClickAttachment = (attachment) => { + emitEvent('fullScreen', attachment.url) } -const onCloseFullscreen = () => { - fullScreenImageUrl.value = null - window.api.fullscreen(false) -} - -const onDownload = (message) => { - window.api.file.download({ - url: message.content, - properties: { - filename: 'image.png', - } - }) -} - -const mdRender = (content) => { - if (store.chatFilter) { - const regex = new RegExp(store.chatFilter, 'gi') - content = content.replace(regex, (match) => `==${match}==`); - } - return window.api.markdown.render(content) +const onImageLoaded = (message) => { + emits('image-loaded', message) } @@ -195,59 +123,8 @@ const mdRender = (content) => { \ No newline at end of file diff --git a/src/components/MessageItemBody.vue b/src/components/MessageItemBody.vue new file mode 100644 index 0000000..76ad865 --- /dev/null +++ b/src/components/MessageItemBody.vue @@ -0,0 +1,82 @@ + + + + + + + \ No newline at end of file diff --git a/src/components/MessageItemImage.vue b/src/components/MessageItemImage.vue new file mode 100644 index 0000000..e7ad1a4 --- /dev/null +++ b/src/components/MessageItemImage.vue @@ -0,0 +1,47 @@ + + + + + \ No newline at end of file diff --git a/src/components/MessageList.vue b/src/components/MessageList.vue index 740bc3a..af10ed5 100644 --- a/src/components/MessageList.vue +++ b/src/components/MessageList.vue @@ -9,6 +9,10 @@ +
+ + +
+ + diff --git a/src/settings/SettingsOpenAI.vue b/src/settings/SettingsOpenAI.vue index ad684af..44a10a7 100644 --- a/src/settings/SettingsOpenAI.vue +++ b/src/settings/SettingsOpenAI.vue @@ -9,28 +9,19 @@
- - -
-
-
- + -
+ More about OpenAI models OpenAI pricing
- +
-