From 29bf64e1a3f66a3f54671b8de219c0cec8fa5de3 Mon Sep 17 00:00:00 2001 From: rainu Date: Wed, 1 Jan 2025 17:21:03 +0100 Subject: [PATCH] display image attachments as image instead of chip --- controller/asset.go | 47 +++++++++++++++++++ controller/build.go | 3 +- frontend/src/components/ChatMessage.vue | 47 ++++++++++++++----- frontend/src/views/Home.vue | 6 +-- .../wailsjs/go/controller/Controller.d.ts | 2 + frontend/wailsjs/go/controller/Controller.js | 4 ++ frontend/wailsjs/go/models.ts | 14 ++++++ 7 files changed, 106 insertions(+), 17 deletions(-) create mode 100644 controller/asset.go diff --git a/controller/asset.go b/controller/asset.go new file mode 100644 index 0000000..6549a0a --- /dev/null +++ b/controller/asset.go @@ -0,0 +1,47 @@ +package controller + +import ( + "fmt" + "github.com/gabriel-vasile/mimetype" + "io" + "net/http" + "os" +) + +type AssetMeta struct { + Path string + MimeType string +} + +func (c *Controller) GetAssetMeta(path string) (AssetMeta, error) { + file, err := os.Open(path) + if err != nil { + println("error open asset file: " + err.Error()) + return AssetMeta{}, fmt.Errorf("error open asset file: %w", err) + } + defer file.Close() + + mime, err := mimetype.DetectReader(file) + if err != nil { + return AssetMeta{}, fmt.Errorf("error detecting mimetype: %w", err) + } + + result := AssetMeta{ + Path: path, + MimeType: mime.String(), + } + + return result, nil +} + +func (c *Controller) handleAsset(resp http.ResponseWriter, req *http.Request) { + file, err := os.Open(req.URL.Path) + if err != nil { + resp.WriteHeader(http.StatusNotFound) + return + } + defer file.Close() + + resp.WriteHeader(http.StatusOK) + io.Copy(resp, file) +} diff --git a/controller/build.go b/controller/build.go index 69e753d..02195e5 100644 --- a/controller/build.go +++ b/controller/build.go @@ -13,6 +13,7 @@ import ( "github.com/wailsapp/wails/v2/pkg/options/mac" "github.com/wailsapp/wails/v2/pkg/options/windows" "log/slog" + "net/http" ) func BuildFromConfig(cfg *config.Config) (ctrl *Controller, err error) { @@ -107,7 +108,7 @@ func GetOptions(c *Controller, icon []byte, assets embed.FS) *options.App { WindowStartState: options.WindowStartState(ac.UI.Window.StartState), AssetServer: &assetserver.Options{ Assets: assets, - Handler: nil, + Handler: http.HandlerFunc(c.handleAsset), Middleware: nil, }, Bind: []interface{}{ diff --git a/frontend/src/components/ChatMessage.vue b/frontend/src/components/ChatMessage.vue index 01fc48c..64028cf 100644 --- a/frontend/src/components/ChatMessage.vue +++ b/frontend/src/components/ChatMessage.vue @@ -5,15 +5,16 @@ - - {{ fileName(attachment) }} - + @@ -30,11 +31,13 @@ import { defineComponent, PropType } from 'vue' import VueMarkdown from 'vue-markdown-render' +import { GetAssetMeta } from '../../wailsjs/go/controller/Controller' +import { controller } from '../../wailsjs/go/models.ts' +import AssetMeta = controller.AssetMeta +import LLMMessageContentPart = controller.LLMMessageContentPart import hljs from 'highlight.js' import { type Options as MarkdownItOptions } from 'markdown-it' import { UseCodeStyle } from './code-style.ts' -import { controller } from '../../wailsjs/go/models.ts' -import LLMMessageContentPart = controller.LLMMessageContentPart export enum Role { User = 'human', @@ -72,6 +75,7 @@ export default defineComponent({ return '' // use external default escaping }, } as MarkdownItOptions, + attachmentsMeta: [] as AssetMeta[], } }, computed: { @@ -87,6 +91,9 @@ export default defineComponent({ attachments() { return this.message.filter((part) => part.Type === ContentType.Attachment).map((part) => part.Content) }, + imageWidth() { + return this.$appConfig.UI.Window.InitialWidth.Value / 5 + }, }, methods: { enrichCopyButtons() { @@ -122,14 +129,28 @@ export default defineComponent({ }) } }, - fileName(path: string) { - return path.split('/').pop() || '' + fileName(asset: AssetMeta) { + return asset.Path.split('/').pop() || '' + }, + isImage(asset: AssetMeta) { + return asset.MimeType.startsWith('image/') }, }, watch: { textMessage() { this.$nextTick(() => this.enrichCopyButtons()) }, + attachments: { + async handler() { + const promises = this.attachments.map((path) => GetAssetMeta(path)) + try { + this.attachmentsMeta = await Promise.all(promises) + } catch (e) { + console.error(e) + } + }, + immediate: true, + }, }, mounted() { UseCodeStyle(this.$appConfig.UI.CodeStyle) diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue index 9e22ef1..549b97a 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home.vue @@ -51,8 +51,8 @@ export default { appbarHeight: 0, progress: false, input: { - prompt: '', - attachments: [] as string[], + prompt: this.$appConfig.UI.Prompt.InitValue, + attachments: this.$appConfig.UI.Prompt.InitAttachments, } as ChatInputType, outputStream: [ { @@ -148,7 +148,7 @@ export default { }, async waitForLLM() { this.input.prompt = this.$appConfig.UI.Prompt.InitValue - this.input.attachments = [] + this.input.attachments = this.$appConfig.UI.Prompt.InitAttachments await this.processLLM(this.input, () => LLMWait()) }, async onInterrupt() { diff --git a/frontend/wailsjs/go/controller/Controller.d.ts b/frontend/wailsjs/go/controller/Controller.d.ts index c243967..03d7e39 100755 --- a/frontend/wailsjs/go/controller/Controller.d.ts +++ b/frontend/wailsjs/go/controller/Controller.d.ts @@ -7,6 +7,8 @@ export function AppMounted():Promise; export function GetApplicationConfig():Promise; +export function GetAssetMeta(arg1:string):Promise; + export function LLMAsk(arg1:controller.LLMAskArgs):Promise; export function LLMInterrupt():Promise; diff --git a/frontend/wailsjs/go/controller/Controller.js b/frontend/wailsjs/go/controller/Controller.js index 1bcde9b..f363951 100755 --- a/frontend/wailsjs/go/controller/Controller.js +++ b/frontend/wailsjs/go/controller/Controller.js @@ -10,6 +10,10 @@ export function GetApplicationConfig() { return window['go']['controller']['Controller']['GetApplicationConfig'](); } +export function GetAssetMeta(arg1) { + return window['go']['controller']['Controller']['GetAssetMeta'](arg1); +} + export function LLMAsk(arg1) { return window['go']['controller']['Controller']['LLMAsk'](arg1); } diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index a958450..3018ef8 100755 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -276,6 +276,20 @@ export namespace config { export namespace controller { + export class AssetMeta { + Path: string; + MimeType: string; + + static createFrom(source: any = {}) { + return new AssetMeta(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.Path = source["Path"]; + this.MimeType = source["MimeType"]; + } + } export class LLMMessageContentPart { Type: string; Content: string;