From 98537825e933da9e1c22809b58a3bd0f0509f23f Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Thu, 9 Jan 2025 05:01:33 +0530 Subject: [PATCH] feat: AI clean up of agent responses, adds new `ai` package - feat: full screen tiptap editor, esentially two editors that attempt to keep their state in sync. - moves tiptap editor menu bar to to show up as a bubble once text is selected. - Layout fixes and improvements. - Improves /reports/overview charts and cards. --- cmd/ai.go | 29 ++++ cmd/conversation.go | 3 + cmd/handlers.go | 4 + cmd/init.go | 14 ++ cmd/main.go | 3 + frontend/src/App.vue | 2 + frontend/src/api/index.js | 6 +- frontend/src/assets/styles/main.scss | 7 +- frontend/src/components/NavBar.vue | 109 ------------ .../src/components/account/AccountPage.vue | 11 -- .../admin/automation/Automation.vue | 2 - .../admin/business_hours/BusinessHours.vue | 4 +- .../src/components/admin/common/MenuCard.vue | 15 +- .../components/admin/common/PageHeader.vue | 19 --- .../canned_responses/CannedResponses.vue | 4 +- .../admin/conversation/status/Status.vue | 4 +- .../admin/conversation/tags/Tags.vue | 4 +- .../src/components/admin/general/General.vue | 4 +- frontend/src/components/admin/inbox/Inbox.vue | 4 +- .../notification/NotificationSetting.vue | 4 +- frontend/src/components/admin/oidc/OIDC.vue | 4 +- frontend/src/components/admin/sla/SLA.vue | 4 +- .../src/components/admin/team/roles/Roles.vue | 4 +- .../src/components/admin/team/teams/Teams.vue | 4 +- .../components/admin/team/users/UsersCard.vue | 4 +- .../components/admin/templates/Templates.vue | 4 +- .../src/components/admin/uploads/Uploads.vue | 4 +- frontend/src/components/common/PageHeader.vue | 33 ++-- .../components/conversation/Conversation.vue | 15 +- .../conversation/ConversationTextEditor.vue | 155 +++++++++-------- .../src/components/conversation/ReplyBox.vue | 157 ++++++++++++------ .../conversation/ReplyBoxMenuBar.vue | 22 +-- .../conversation/list/ConversationList.vue | 11 +- .../components/dashboard/DashboardCard.vue | 24 ++- .../dashboard/DashboardLineChart.vue | 22 ++- .../src/components/message/MessageList.vue | 2 +- frontend/src/router/index.js | 88 +++++----- frontend/src/views/DashboardView.vue | 45 ++--- internal/ai/ai.go | 72 ++++---- internal/ai/models/models.go | 25 ++- internal/ai/openai.go | 16 +- internal/ai/queries.sql | 9 +- internal/conversation/conversation.go | 4 +- internal/conversation/queries.sql | 48 +++++- schema.sql | 49 +++++- 45 files changed, 582 insertions(+), 495 deletions(-) create mode 100644 cmd/ai.go delete mode 100644 frontend/src/components/NavBar.vue delete mode 100644 frontend/src/components/admin/common/PageHeader.vue diff --git a/cmd/ai.go b/cmd/ai.go new file mode 100644 index 0000000..26be0dd --- /dev/null +++ b/cmd/ai.go @@ -0,0 +1,29 @@ +package main + +import "github.com/zerodha/fastglue" + +// handleAICompletion handles AI completion requests +func handleAICompletion(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + promptKey = string(r.RequestCtx.PostArgs().Peek("prompt_key")) + content = string(r.RequestCtx.PostArgs().Peek("content")) + ) + resp, err := app.ai.SendPrompt(promptKey, content) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(resp) +} + +// handleGetAIPrompts returns AI prompts +func handleGetAIPrompts(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + resp, err := app.ai.GetPrompts() + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(resp) +} diff --git a/cmd/conversation.go b/cmd/conversation.go index 4cae9ba..f68c8bf 100644 --- a/cmd/conversation.go +++ b/cmd/conversation.go @@ -457,6 +457,9 @@ func handleUpdateConversationStatus(r *fastglue.Request) error { if !allowed { return sendErrorEnvelope(r, envelope.NewError(envelope.PermissionError, "Permission denied", nil)) } + if string(status) == cmodels.StatusResolved && conversation.AssignedUserID.Int == 0 { + return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, "Cannot resolve the conversation without an assigned user. Please assign a user before attempting to resolve.", nil)) + } if err := app.conversation.UpdateConversationStatus(uuid, status, snoozedUntil, user); err != nil { return sendErrorEnvelope(r, err) diff --git a/cmd/handlers.go b/cmd/handlers.go index 5202db8..c288112 100644 --- a/cmd/handlers.go +++ b/cmd/handlers.go @@ -165,6 +165,10 @@ func initHandlers(g *fastglue.Fastglue, hub *ws.Hub) { g.PUT("/api/v1/sla/{id}", perm(fastglue.ReqLenRangeParams(handleUpdateSLA, slaReqFields), "sla:manage")) g.DELETE("/api/v1/sla/{id}", perm(handleDeleteSLA, "sla:manage")) + // AI. + g.GET("/api/v1/ai/prompts", auth(handleGetAIPrompts)) + g.POST("/api/v1/ai/completion", auth(handleAICompletion)) + // WebSocket. g.GET("/ws", auth(func(r *fastglue.Request) error { return handleWS(r, hub) diff --git a/cmd/init.go b/cmd/init.go index bac5dc2..fe7ac65 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -12,6 +12,7 @@ import ( "html/template" + "github.com/abhinavxd/artemis/internal/ai" auth_ "github.com/abhinavxd/artemis/internal/auth" "github.com/abhinavxd/artemis/internal/authz" "github.com/abhinavxd/artemis/internal/autoassigner" @@ -701,6 +702,19 @@ func initPriority(db *sqlx.DB) *priority.Manager { return manager } +// initAI inits AI manager. +func initAI(db *sqlx.DB) *ai.Manager { + lo := initLogger("ai") + m, err := ai.New(ai.Opts{ + DB: db, + Lo: lo, + }) + if err != nil { + log.Fatalf("error initializing AI manager: %v", err) + } + return m +} + // initLogger initializes a logf logger. func initLogger(src string) *logf.Logger { lvl, env := ko.MustString("app.log_level"), ko.MustString("app.env") diff --git a/cmd/main.go b/cmd/main.go index 5764b46..57aec6f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -8,6 +8,7 @@ import ( "os/signal" "syscall" + "github.com/abhinavxd/artemis/internal/ai" auth_ "github.com/abhinavxd/artemis/internal/auth" "github.com/abhinavxd/artemis/internal/authz" businesshours "github.com/abhinavxd/artemis/internal/business_hours" @@ -73,6 +74,7 @@ type App struct { sla *sla.Manager csat *csat.Manager view *view.Manager + ai *ai.Manager notifier *notifier.Service } @@ -205,6 +207,7 @@ func main() { priority: initPriority(db), role: initRole(db), tag: initTag(db), + ai: initAI(db), cannedResp: initCannedResponse(db), } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 09ae93c..ccde5cd 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -7,6 +7,7 @@
+
@@ -28,6 +29,7 @@ import { EMITTER_EVENTS } from '@/constants/emitterEvents.js' import { useEmitter } from '@/composables/useEmitter' import { handleHTTPError } from '@/utils/http' import { useConversationStore } from './stores/conversation' +import PageHeader from './components/common/PageHeader.vue' import ViewForm from '@/components/ViewForm.vue' import api from '@/api' import Sidebar from '@/components/sidebar/Sidebar.vue' diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 25c3a4d..81e5aca 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -239,6 +239,8 @@ const updateView = (id, data) => } }) const deleteView = (id) => http.delete(`/api/v1/views/me/${id}`) +const getAiPrompts = () => http.get('/api/v1/ai/prompts') +const aiCompletion = (data) => http.post('/api/v1/ai/completion', data) export default { login, @@ -337,5 +339,7 @@ export default { getCurrentUserViews, createView, updateView, - deleteView + deleteView, + getAiPrompts, + aiCompletion } diff --git a/frontend/src/assets/styles/main.scss b/frontend/src/assets/styles/main.scss index e0b6bd7..b782aaa 100644 --- a/frontend/src/assets/styles/main.scss +++ b/frontend/src/assets/styles/main.scss @@ -8,14 +8,11 @@ font-size: 16px; } -body { - overflow-x: hidden; - overflow-y: hidden; -} - .page-content { padding: 1rem 1rem; height: 100%; + overflow-y: scroll; + padding-bottom: 50px; } // Theme. diff --git a/frontend/src/components/NavBar.vue b/frontend/src/components/NavBar.vue deleted file mode 100644 index ee37c16..0000000 --- a/frontend/src/components/NavBar.vue +++ /dev/null @@ -1,109 +0,0 @@ - - - diff --git a/frontend/src/components/account/AccountPage.vue b/frontend/src/components/account/AccountPage.vue index 8e57a7a..ce16b14 100644 --- a/frontend/src/components/account/AccountPage.vue +++ b/frontend/src/components/account/AccountPage.vue @@ -1,19 +1,8 @@