From 26d76c966f82b78b9c74f68d0a1a3de43d8f351d Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Sat, 1 Mar 2025 19:40:18 +0530 Subject: [PATCH] feat: allow setting OpenAI API KEY from the UI. feat: new `ai:manage` permission for the same Migrations for new role. --- cmd/ai.go | 25 ++++- cmd/handlers.go | 1 + frontend/src/api/index.js | 2 + .../src/features/admin/roles/RoleForm.vue | 29 ++++-- .../conversation/MacroActionsPreview.vue | 4 +- .../src/features/conversation/ReplyBox.vue | 93 ++++++++++++++++++- internal/ai/ai.go | 33 +++++++ internal/ai/openai.go | 8 +- internal/ai/queries.sql | 11 ++- internal/authz/models/models.go | 4 + internal/migrations/v0.4.0.go | 18 ++++ schema.sql | 20 ++-- 12 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 internal/migrations/v0.4.0.go diff --git a/cmd/ai.go b/cmd/ai.go index ca3b337..e940ff7 100644 --- a/cmd/ai.go +++ b/cmd/ai.go @@ -1,6 +1,14 @@ package main -import "github.com/zerodha/fastglue" +import ( + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/zerodha/fastglue" +) + +type providerUpdateReq struct { + Provider string `json:"provider"` + APIKey string `json:"api_key"` +} // handleAICompletion handles AI completion requests func handleAICompletion(r *fastglue.Request) error { @@ -27,3 +35,18 @@ func handleGetAIPrompts(r *fastglue.Request) error { } return r.SendEnvelope(resp) } + +// handleUpdateAIProvider updates the AI provider +func handleUpdateAIProvider(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + req providerUpdateReq + ) + if err := r.Decode(&req, "json"); err != nil { + return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, "Error unmarshalling request", nil)) + } + if err := app.ai.UpdateProvider(req.Provider, req.APIKey); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope("Provider updated successfully") +} diff --git a/cmd/handlers.go b/cmd/handlers.go index dbb31b5..1c26540 100644 --- a/cmd/handlers.go +++ b/cmd/handlers.go @@ -174,6 +174,7 @@ func initHandlers(g *fastglue.Fastglue, hub *ws.Hub) { // AI completion. g.GET("/api/v1/ai/prompts", auth(handleGetAIPrompts)) g.POST("/api/v1/ai/completion", auth(handleAICompletion)) + g.PUT("/api/v1/ai/provider", perm(handleUpdateAIProvider, "ai:manage")) // WebSocket. g.GET("/ws", auth(func(r *fastglue.Request) error { diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 013013c..2119100 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -265,6 +265,7 @@ 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) +const updateAIProvider = (data) => http.put('/api/v1/ai/provider', data) export default { login, @@ -328,6 +329,7 @@ export default { updateAutomationRule, updateAutomationRuleWeights, updateAutomationRulesExecutionMode, + updateAIProvider, createAutomationRule, toggleAutomationRule, deleteAutomationRule, diff --git a/frontend/src/features/admin/roles/RoleForm.vue b/frontend/src/features/admin/roles/RoleForm.vue index 4813657..2f874c4 100644 --- a/frontend/src/features/admin/roles/RoleForm.vue +++ b/frontend/src/features/admin/roles/RoleForm.vue @@ -13,7 +13,11 @@ Description - + @@ -24,13 +28,19 @@

{{ entity.name }}

- +
- + {{ permission.label }}
@@ -69,7 +79,7 @@ const props = defineProps({ }, isLoading: { type: Boolean, - required: false, + required: false } }) @@ -77,7 +87,7 @@ const permissions = ref([ { name: 'Conversation', permissions: [ - { name: 'conversations:read', label: 'View conversations' }, + { name: 'conversations:read', label: 'View conversation' }, { name: 'conversations:read_assigned', label: 'View conversations assigned to me' }, { name: 'conversations:read_all', label: 'View all conversations' }, { name: 'conversations:read_unassigned', label: 'View all unassigned conversations' }, @@ -89,7 +99,7 @@ const permissions = ref([ { name: 'conversations:update_tags', label: 'Add or remove conversation tags' }, { name: 'messages:read', label: 'View conversation messages' }, { name: 'messages:write', label: 'Send messages in conversations' }, - { name: 'view:manage', label: 'Create and manage conversation views' }, + { name: 'view:manage', label: 'Create and manage conversation views' } ] }, { @@ -110,8 +120,9 @@ const permissions = ref([ { name: 'reports:manage', label: 'Manage Reports' }, { name: 'business_hours:manage', label: 'Manage Business Hours' }, { name: 'sla:manage', label: 'Manage SLA Policies' }, + { name: 'ai:manage', label: 'Manage AI Features' } ] - }, + } ]) const selectedPermissions = ref([]) diff --git a/frontend/src/features/conversation/MacroActionsPreview.vue b/frontend/src/features/conversation/MacroActionsPreview.vue index a07b66a..572fb19 100644 --- a/frontend/src/features/conversation/MacroActionsPreview.vue +++ b/frontend/src/features/conversation/MacroActionsPreview.vue @@ -1,12 +1,12 @@