From e6bbd83c6b1acc02c0f6ad13e8d82a0006fff17d Mon Sep 17 00:00:00 2001 From: RockYang Date: Thu, 22 Feb 2024 17:16:44 +0800 Subject: [PATCH] feat: allow to view chat message in manager console --- CHANGELOG.md | 2 + api/handler/admin/chat_handler.go | 244 ++++++++++++++ api/handler/admin/dashboard_handler.go | 2 +- api/handler/admin/user_handler.go | 2 +- api/handler/chatimpl/azure_handler.go | 4 +- api/handler/chatimpl/baidu_handler.go | 4 +- api/handler/chatimpl/chat_handler.go | 4 +- api/handler/chatimpl/chat_item_handler.go | 4 +- api/handler/chatimpl/chatglm_handler.go | 4 +- api/handler/chatimpl/openai_handler.go | 6 +- api/handler/chatimpl/qwen_handler.go | 4 +- api/handler/chatimpl/xunfei_handler.go | 4 +- api/handler/function_handler.go | 3 +- api/main.go | 10 +- api/service/mj/plus/client.go | 2 + api/service/sms/service_manager.go | 2 +- api/store/model/chat_history.go | 4 +- web/src/components/admin/AdminSidebar.vue | 5 + web/src/router.js | 6 + web/src/views/ChatPlus.vue | 1 - web/src/views/Invitation.vue | 9 +- web/src/views/admin/ChatList.vue | 386 ++++++++++++++++++++++ web/src/views/admin/Login.vue | 2 + 23 files changed, 688 insertions(+), 26 deletions(-) create mode 100644 api/handler/admin/chat_handler.go create mode 100644 web/src/views/admin/ChatList.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 48c96c50..eb106054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ * Bug修复:对话输入HTML标签不显示的问题 * 功能优化:gpt-4-all/gpts/midjourney-plus 支持第三方平台的 API KEY * 功能新增:新增删除文件功能 +* Bug修复:解决 MJ-Plus discord 图片下载失败问题,使用第三方平台中转地址下载 +* 功能新增:后台管理新怎对话查看和检索功能 ## v3.2.6 * 功能优化:恢复关闭注册系统配置项,管理员可以在后台关闭用户注册,只允许内部添加账号 diff --git a/api/handler/admin/chat_handler.go b/api/handler/admin/chat_handler.go new file mode 100644 index 00000000..2f931e62 --- /dev/null +++ b/api/handler/admin/chat_handler.go @@ -0,0 +1,244 @@ +package admin + +import ( + "chatplus/core" + "chatplus/core/types" + "chatplus/handler" + "chatplus/store/model" + "chatplus/store/vo" + "chatplus/utils" + "chatplus/utils/resp" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type ChatHandler struct { + handler.BaseHandler + db *gorm.DB +} + +func NewChatHandler(app *core.AppServer, db *gorm.DB) *ChatHandler { + h := ChatHandler{db: db} + h.App = app + return &h +} + +type chatItemVo struct { + Username string `json:"username"` + UserId uint `json:"user_id"` + ChatId string `json:"chat_id"` + Title string `json:"title"` + Model string `json:"model"` + Token int `json:"token"` + CreatedAt int64 `json:"created_at"` + MsgNum int `json:"msg_num"` // 消息数量 +} + +func (h *ChatHandler) List(c *gin.Context) { + var data struct { + Title string `json:"title"` + UserId uint `json:"user_id"` + Model string `json:"model"` + CreateAt []string `json:"created_time"` + Page int `json:"page"` + PageSize int `json:"page_size"` + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + session := h.db.Session(&gorm.Session{}) + if data.Title != "" { + session = session.Where("title LIKE ?", "%"+data.Title+"%") + } + if data.UserId > 0 { + session = session.Where("user_id = ?", data.UserId) + } + if data.Model != "" { + session = session.Where("model = ?", data.Model) + } + if len(data.CreateAt) == 2 { + start := utils.Str2stamp(data.CreateAt[0] + " 00:00:00") + end := utils.Str2stamp(data.CreateAt[1] + " 00:00:00") + session = session.Where("created_at >= ? AND created_at <= ?", start, end) + } + + var total int64 + session.Model(&model.ChatItem{}).Count(&total) + var items []model.ChatItem + var list = make([]chatItemVo, 0) + offset := (data.Page - 1) * data.PageSize + res := session.Order("id DESC").Offset(offset).Limit(data.PageSize).Find(&items) + if res.Error == nil { + userIds := make([]uint, 0) + chatIds := make([]string, 0) + for _, item := range items { + userIds = append(userIds, item.UserId) + chatIds = append(chatIds, item.ChatId) + } + var messages []model.ChatMessage + var users []model.User + h.db.Where("chat_id IN ?", chatIds).Find(&messages) + h.db.Where("id IN ?", userIds).Find(&users) + + tokenMap := make(map[string]int) + userMap := make(map[uint]string) + msgMap := make(map[string]int) + for _, msg := range messages { + tokenMap[msg.ChatId] += msg.Tokens + msgMap[msg.ChatId] += 1 + } + for _, user := range users { + userMap[user.Id] = user.Username + } + for _, item := range items { + list = append(list, chatItemVo{ + UserId: item.UserId, + Username: userMap[item.UserId], + ChatId: item.ChatId, + Title: item.Title, + Model: item.Model, + Token: tokenMap[item.ChatId], + MsgNum: msgMap[item.ChatId], + CreatedAt: item.CreatedAt.Unix(), + }) + } + } + resp.SUCCESS(c, vo.NewPage(total, data.Page, data.PageSize, list)) +} + +type chatMessageVo struct { + Id uint `json:"id"` + UserId uint `json:"user_id"` + Username string `json:"username"` + Content string `json:"content"` + Type string `json:"type"` + Model string `json:"model"` + Token int `json:"token"` + Icon string `json:"icon"` + CreatedAt int64 `json:"created_at"` +} + +// Messages 读取聊天记录列表 +func (h *ChatHandler) Messages(c *gin.Context) { + var data struct { + UserId uint `json:"user_id"` + Content string `json:"content"` + Model string `json:"model"` + CreateAt []string `json:"created_time"` + Page int `json:"page"` + PageSize int `json:"page_size"` + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + session := h.db.Session(&gorm.Session{}) + if data.Content != "" { + session = session.Where("content LIKE ?", "%"+data.Content+"%") + } + if data.UserId > 0 { + session = session.Where("user_id = ?", data.UserId) + } + if data.Model != "" { + session = session.Where("model = ?", data.Model) + } + if len(data.CreateAt) == 2 { + start := utils.Str2stamp(data.CreateAt[0] + " 00:00:00") + end := utils.Str2stamp(data.CreateAt[1] + " 00:00:00") + session = session.Where("created_at >= ? AND created_at <= ?", start, end) + } + + var total int64 + session.Model(&model.ChatMessage{}).Count(&total) + var items []model.ChatMessage + var list = make([]chatMessageVo, 0) + offset := (data.Page - 1) * data.PageSize + res := session.Order("id DESC").Offset(offset).Limit(data.PageSize).Find(&items) + if res.Error == nil { + userIds := make([]uint, 0) + for _, item := range items { + userIds = append(userIds, item.UserId) + } + var users []model.User + h.db.Where("id IN ?", userIds).Find(&users) + userMap := make(map[uint]string) + for _, user := range users { + userMap[user.Id] = user.Username + } + for _, item := range items { + list = append(list, chatMessageVo{ + Id: item.Id, + UserId: item.UserId, + Username: userMap[item.UserId], + Content: item.Content, + Model: item.Model, + Token: item.Tokens, + Icon: item.Icon, + Type: item.Type, + CreatedAt: item.CreatedAt.Unix(), + }) + } + } + resp.SUCCESS(c, vo.NewPage(total, data.Page, data.PageSize, list)) +} + +// History 获取聊天历史记录 +func (h *ChatHandler) History(c *gin.Context) { + chatId := c.Query("chat_id") // 会话 ID + var items []model.ChatMessage + var messages = make([]vo.HistoryMessage, 0) + res := h.db.Where("chat_id = ?", chatId).Find(&items) + if res.Error != nil { + resp.ERROR(c, "No history message") + return + } else { + for _, item := range items { + var v vo.HistoryMessage + err := utils.CopyObject(item, &v) + v.CreatedAt = item.CreatedAt.Unix() + v.UpdatedAt = item.UpdatedAt.Unix() + if err == nil { + messages = append(messages, v) + } + } + } + + resp.SUCCESS(c, messages) +} + +// RemoveChat 删除对话 +func (h *ChatHandler) RemoveChat(c *gin.Context) { + chatId := h.GetTrim(c, "chat_id") + tx := h.db.Begin() + // 删除聊天记录 + res := tx.Unscoped().Where("chat_id = ?", chatId).Delete(&model.ChatMessage{}) + if res.Error != nil { + resp.ERROR(c, "failed to remove chat message") + return + } + + // 删除对话 + res = tx.Unscoped().Where("chat_id = ?", chatId).Delete(model.ChatItem{}) + if res.Error != nil { + tx.Rollback() // 回滚 + resp.ERROR(c, "failed to remove chat") + return + } + + tx.Commit() + resp.SUCCESS(c) +} + +// RemoveMessage 删除聊天记录 +func (h *ChatHandler) RemoveMessage(c *gin.Context) { + id := h.GetInt(c, "id", 0) + tx := h.db.Unscoped().Delete(&model.ChatMessage{}, id) + if tx.Error != nil { + resp.ERROR(c, "更新数据库失败!") + return + } + resp.SUCCESS(c) +} diff --git a/api/handler/admin/dashboard_handler.go b/api/handler/admin/dashboard_handler.go index 7b5cc9b4..ba2b1c53 100644 --- a/api/handler/admin/dashboard_handler.go +++ b/api/handler/admin/dashboard_handler.go @@ -48,7 +48,7 @@ func (h *DashboardHandler) Stats(c *gin.Context) { } // tokens took stats - var historyMessages []model.HistoryMessage + var historyMessages []model.ChatMessage res = h.db.Where("created_at > ?", zeroTime).Find(&historyMessages) for _, item := range historyMessages { stats.Tokens += item.Tokens diff --git a/api/handler/admin/user_handler.go b/api/handler/admin/user_handler.go index 883569b5..eb1d8168 100644 --- a/api/handler/admin/user_handler.go +++ b/api/handler/admin/user_handler.go @@ -176,7 +176,7 @@ func (h *UserHandler) Remove(c *gin.Context) { return } // 删除聊天历史记录 - res = h.db.Where("user_id = ?", id).Delete(&model.HistoryMessage{}) + res = h.db.Where("user_id = ?", id).Delete(&model.ChatMessage{}) if res.Error != nil { tx.Rollback() resp.ERROR(c, "删除失败") diff --git a/api/handler/chatimpl/azure_handler.go b/api/handler/chatimpl/azure_handler.go index 302ae539..460ac9d7 100644 --- a/api/handler/chatimpl/azure_handler.go +++ b/api/handler/chatimpl/azure_handler.go @@ -126,7 +126,7 @@ func (h *ChatHandler) sendAzureMessage( if err != nil { logger.Error(err) } - historyUserMsg := model.HistoryMessage{ + historyUserMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, @@ -148,7 +148,7 @@ func (h *ChatHandler) sendAzureMessage( totalTokens, _ := utils.CalcTokens(message.Content, req.Model) totalTokens += getTotalTokens(req) - historyReplyMsg := model.HistoryMessage{ + historyReplyMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, diff --git a/api/handler/chatimpl/baidu_handler.go b/api/handler/chatimpl/baidu_handler.go index 7771d2c3..85f786da 100644 --- a/api/handler/chatimpl/baidu_handler.go +++ b/api/handler/chatimpl/baidu_handler.go @@ -151,7 +151,7 @@ func (h *ChatHandler) sendBaiduMessage( if err != nil { logger.Error(err) } - historyUserMsg := model.HistoryMessage{ + historyUserMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, @@ -173,7 +173,7 @@ func (h *ChatHandler) sendBaiduMessage( // 计算本次对话消耗的总 token 数量 replyToken, _ := utils.CalcTokens(message.Content, req.Model) totalTokens := replyToken + getTotalTokens(req) - historyReplyMsg := model.HistoryMessage{ + historyReplyMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index 4b150554..d919c63d 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -325,7 +325,7 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio // loading recent chat history as chat context if chatConfig.ContextDeep > 0 { - var historyMessages []model.HistoryMessage + var historyMessages []model.ChatMessage res := h.db.Debug().Where("chat_id = ? and use_context = 1", session.ChatId).Limit(chatConfig.ContextDeep).Order("id desc").Find(&historyMessages) if res.Error == nil { for i := len(historyMessages) - 1; i >= 0; i-- { @@ -390,7 +390,7 @@ func (h *ChatHandler) Tokens(c *gin.Context) { // 如果没有传入 text 字段,则说明是获取当前 reply 总的 token 消耗(带上下文) if data.Text == "" && data.ChatId != "" { - var item model.HistoryMessage + var item model.ChatMessage userId, _ := c.Get(types.LoginUserID) res := h.db.Where("user_id = ?", userId).Where("chat_id = ?", data.ChatId).Last(&item) if res.Error != nil { diff --git a/api/handler/chatimpl/chat_item_handler.go b/api/handler/chatimpl/chat_item_handler.go index 44af0a68..68996785 100644 --- a/api/handler/chatimpl/chat_item_handler.go +++ b/api/handler/chatimpl/chat_item_handler.go @@ -95,7 +95,7 @@ func (h *ChatHandler) Clear(c *gin.Context) { return res.Error } - res = h.db.Where("user_id = ? AND chat_id IN ?", user.Id, chatIds).Delete(&model.HistoryMessage{}) + res = h.db.Where("user_id = ? AND chat_id IN ?", user.Id, chatIds).Delete(&model.ChatMessage{}) if res.Error != nil { return res.Error } @@ -116,7 +116,7 @@ func (h *ChatHandler) Clear(c *gin.Context) { // History 获取聊天历史记录 func (h *ChatHandler) History(c *gin.Context) { chatId := c.Query("chat_id") // 会话 ID - var items []model.HistoryMessage + var items []model.ChatMessage var messages = make([]vo.HistoryMessage, 0) res := h.db.Where("chat_id = ?", chatId).Find(&items) if res.Error != nil { diff --git a/api/handler/chatimpl/chatglm_handler.go b/api/handler/chatimpl/chatglm_handler.go index 00b88325..d2ced37d 100644 --- a/api/handler/chatimpl/chatglm_handler.go +++ b/api/handler/chatimpl/chatglm_handler.go @@ -130,7 +130,7 @@ func (h *ChatHandler) sendChatGLMMessage( if err != nil { logger.Error(err) } - historyUserMsg := model.HistoryMessage{ + historyUserMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, @@ -152,7 +152,7 @@ func (h *ChatHandler) sendChatGLMMessage( // 计算本次对话消耗的总 token 数量 replyToken, _ := utils.CalcTokens(message.Content, req.Model) totalTokens := replyToken + getTotalTokens(req) - historyReplyMsg := model.HistoryMessage{ + historyReplyMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, diff --git a/api/handler/chatimpl/openai_handler.go b/api/handler/chatimpl/openai_handler.go index 3c228ead..e7105c9f 100644 --- a/api/handler/chatimpl/openai_handler.go +++ b/api/handler/chatimpl/openai_handler.go @@ -46,6 +46,8 @@ func (h *ChatHandler) sendOpenAiMessage( utils.ReplyMessage(ws, ErrorMsg) utils.ReplyMessage(ws, ErrImg) + all, _ := io.ReadAll(response.Body) + logger.Error(string(all)) return err } else { defer response.Body.Close() @@ -197,7 +199,7 @@ func (h *ChatHandler) sendOpenAiMessage( if err != nil { logger.Error(err) } - historyUserMsg := model.HistoryMessage{ + historyUserMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, @@ -227,7 +229,7 @@ func (h *ChatHandler) sendOpenAiMessage( } totalTokens += getTotalTokens(req) - historyReplyMsg := model.HistoryMessage{ + historyReplyMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, diff --git a/api/handler/chatimpl/qwen_handler.go b/api/handler/chatimpl/qwen_handler.go index f7805304..116e8788 100644 --- a/api/handler/chatimpl/qwen_handler.go +++ b/api/handler/chatimpl/qwen_handler.go @@ -151,7 +151,7 @@ func (h *ChatHandler) sendQWenMessage( if err != nil { logger.Error(err) } - historyUserMsg := model.HistoryMessage{ + historyUserMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, @@ -173,7 +173,7 @@ func (h *ChatHandler) sendQWenMessage( // 计算本次对话消耗的总 token 数量 replyToken, _ := utils.CalcTokens(message.Content, req.Model) totalTokens := replyToken + getTotalTokens(req) - historyReplyMsg := model.HistoryMessage{ + historyReplyMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, diff --git a/api/handler/chatimpl/xunfei_handler.go b/api/handler/chatimpl/xunfei_handler.go index f0890403..27e87eed 100644 --- a/api/handler/chatimpl/xunfei_handler.go +++ b/api/handler/chatimpl/xunfei_handler.go @@ -189,7 +189,7 @@ func (h *ChatHandler) sendXunFeiMessage( if err != nil { logger.Error(err) } - historyUserMsg := model.HistoryMessage{ + historyUserMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, @@ -211,7 +211,7 @@ func (h *ChatHandler) sendXunFeiMessage( // 计算本次对话消耗的总 token 数量 replyToken, _ := utils.CalcTokens(message.Content, req.Model) totalTokens := replyToken + getTotalTokens(req) - historyReplyMsg := model.HistoryMessage{ + historyReplyMsg := model.ChatMessage{ UserId: userVo.Id, ChatId: session.ChatId, RoleId: role.Id, diff --git a/api/handler/function_handler.go b/api/handler/function_handler.go index 6b092870..a96bf6d5 100644 --- a/api/handler/function_handler.go +++ b/api/handler/function_handler.go @@ -247,7 +247,7 @@ func (h *FunctionHandler) Dall3(c *gin.Context) { } else { request = req.C().R() } - logger.Debugf("Sending %s request, ApiURL:%s, Password:%s, PROXY: %s", apiKey.Platform, apiKey.ApiURL, apiKey.Value, h.proxyURL) + logger.Debugf("Sending %s request, ApiURL:%s, API KEY:%s, PROXY: %s", apiKey.Platform, apiKey.ApiURL, apiKey.Value, h.proxyURL) r, err := request.SetHeader("Content-Type", "application/json"). SetHeader("Authorization", "Bearer "+apiKey.Value). SetBody(imgReq{ @@ -264,6 +264,7 @@ func (h *FunctionHandler) Dall3(c *gin.Context) { } // 更新 API KEY 的最后使用时间 h.db.Model(&apiKey).UpdateColumn("last_used_at", time.Now().Unix()) + logger.Debugf("%+v", res) // 存储图片 imgURL, err := h.uploadManager.GetUploadHandler().PutImg(res.Data[0].Url, false) if err != nil { diff --git a/api/main.go b/api/main.go index 78385d44..3bc16790 100644 --- a/api/main.go +++ b/api/main.go @@ -136,6 +136,7 @@ func main() { fx.Provide(admin.NewChatModelHandler), fx.Provide(admin.NewProductHandler), fx.Provide(admin.NewOrderHandler), + fx.Provide(admin.NewChatHandler), // 创建服务 fx.Provide(sms.NewSendServiceManager), @@ -372,7 +373,14 @@ func main() { group.POST("zaobao", h.ZaoBao) group.POST("dalle3", h.Dall3) }), - + fx.Invoke(func(s *core.AppServer, h *admin.ChatHandler) { + group := s.Engine.Group("/api/admin/chat/") + group.POST("list", h.List) + group.POST("message", h.Messages) + group.GET("history", h.History) + group.GET("remove", h.RemoveChat) + group.GET("message/remove", h.RemoveMessage) + }), fx.Provide(handler.NewTestHandler), fx.Invoke(func(s *core.AppServer, h *handler.TestHandler) { s.Engine.GET("/api/test", h.Test) diff --git a/api/service/mj/plus/client.go b/api/service/mj/plus/client.go index 6dc03af0..fe525345 100644 --- a/api/service/mj/plus/client.go +++ b/api/service/mj/plus/client.go @@ -90,6 +90,8 @@ func (c *Client) Imagine(task types.MjTask) (ImageRes, error) { SetErrorResult(&errRes). Post(apiURL) if err != nil { + errStr, _ := io.ReadAll(r.Body) + logger.Errorf("API 返回:%s, API URL: %s", string(errStr), apiURL) return ImageRes{}, fmt.Errorf("请求 API 出错:%v", err) } diff --git a/api/service/sms/service_manager.go b/api/service/sms/service_manager.go index abedea96..c360cc0f 100644 --- a/api/service/sms/service_manager.go +++ b/api/service/sms/service_manager.go @@ -14,7 +14,7 @@ var logger = logger2.GetLogger() func NewSendServiceManager(config *types.AppConfig) (*ServiceManager, error) { active := Ali - if config.OSS.Active != "" { + if config.SMS.Active != "" { active = strings.ToUpper(config.SMS.Active) } var handler Service diff --git a/api/store/model/chat_history.go b/api/store/model/chat_history.go index 395f2b3d..36abeb4e 100644 --- a/api/store/model/chat_history.go +++ b/api/store/model/chat_history.go @@ -2,7 +2,7 @@ package model import "gorm.io/gorm" -type HistoryMessage struct { +type ChatMessage struct { BaseModel ChatId string // 会话 ID UserId uint // 用户 ID @@ -16,6 +16,6 @@ type HistoryMessage struct { DeletedAt gorm.DeletedAt } -func (HistoryMessage) TableName() string { +func (ChatMessage) TableName() string { return "chatgpt_chat_history" } diff --git a/web/src/components/admin/AdminSidebar.vue b/web/src/components/admin/AdminSidebar.vue index 0dc5e898..afa7068c 100644 --- a/web/src/components/admin/AdminSidebar.vue +++ b/web/src/components/admin/AdminSidebar.vue @@ -116,6 +116,11 @@ const items = [ index: '/admin/functions', title: '函数管理', }, + { + icon: 'prompt', + index: '/admin/chats', + title: '对话管理', + }, { icon: 'config', index: '/admin/system', diff --git a/web/src/router.js b/web/src/router.js index 6e409855..80a4bded 100644 --- a/web/src/router.js +++ b/web/src/router.js @@ -156,6 +156,12 @@ const routes = [ meta: {title: '函数管理'}, component: () => import('@/views/admin/Functions.vue'), }, + { + path: '/admin/chats', + name: 'admin-chats', + meta: {title: '对话管理'}, + component: () => import('@/views/admin/ChatList.vue'), + }, ] }, diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index cfdc6f18..5635eac6 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -262,7 +262,6 @@ import 'highlight.js/styles/a11y-dark.css' import { dateFormat, escapeHTML, - isImage, isMobile, processContent, randString, diff --git a/web/src/views/Invitation.vue b/web/src/views/Invitation.vue index cc7b17a5..4269d0a8 100644 --- a/web/src/views/Invitation.vue +++ b/web/src/views/Invitation.vue @@ -1,6 +1,6 @@