feat(copilot): finish configuration center
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gochat/gochat/internal/llm"
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
"github.com/gochat/gochat/internal/service"
|
||||
applogger "github.com/gochat/gochat/pkg/logger"
|
||||
"github.com/gochat/gochat/pkg/response"
|
||||
)
|
||||
|
||||
@@ -16,12 +19,24 @@ import (
|
||||
type CopilotConfigHandler struct {
|
||||
platform *service.CopilotConfigService
|
||||
account *service.CaptainPreferenceService
|
||||
audit *service.AuditService
|
||||
articles *service.ArticleService
|
||||
}
|
||||
|
||||
func NewCopilotConfigHandler(platform *service.CopilotConfigService, account *service.CaptainPreferenceService) *CopilotConfigHandler {
|
||||
return &CopilotConfigHandler{platform: platform, account: account}
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) WithAuditService(audit *service.AuditService) *CopilotConfigHandler {
|
||||
h.audit = audit
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) WithArticleService(articles *service.ArticleService) *CopilotConfigHandler {
|
||||
h.articles = articles
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) PlatformGet(c *gin.Context) {
|
||||
payload, err := h.platform.Get(c.Request.Context())
|
||||
if err != nil {
|
||||
@@ -42,9 +57,62 @@ func (h *CopilotConfigHandler) PlatformUpdate(c *gin.Context) {
|
||||
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
h.recordPlatformUpdate(c, input, payload)
|
||||
c.JSON(http.StatusOK, payload)
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) recordPlatformUpdate(c *gin.Context, input service.CopilotProviderConfigInput, payload *service.CopilotProviderConfigPayload) {
|
||||
if h.audit == nil || payload == nil {
|
||||
return
|
||||
}
|
||||
changes := map[string]any{
|
||||
"chat": map[string]any{
|
||||
"provider": payload.Chat.Provider,
|
||||
"base_url": payload.Chat.BaseURL,
|
||||
"model": payload.Chat.Model,
|
||||
"api_key_configured": payload.Chat.APIKey.Configured,
|
||||
"api_key_changed": input.Chat.APIKey != "" || input.Chat.ClearAPIKey,
|
||||
},
|
||||
"embedding": map[string]any{
|
||||
"mode": payload.Embedding.Mode,
|
||||
"provider": payload.Embedding.Provider,
|
||||
"base_url": payload.Embedding.BaseURL,
|
||||
"model": payload.Embedding.Model,
|
||||
"dimensions": payload.Embedding.Dimensions,
|
||||
"api_key_configured": payload.Embedding.APIKey.Configured,
|
||||
"api_key_changed": input.Embedding.APIKey != "" || input.Embedding.ClearAPIKey,
|
||||
},
|
||||
"generation": payload.Generation,
|
||||
"request": payload.Request,
|
||||
"configured": payload.Configured,
|
||||
}
|
||||
raw, err := json.Marshal(changes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
audit := &model.Audit{
|
||||
AuditableType: "InstallationConfig",
|
||||
AuditableID: 1,
|
||||
Action: "update",
|
||||
AuditedChanges: raw,
|
||||
RemoteAddress: c.ClientIP(),
|
||||
RequestUUID: firstNonEmpty(c.GetHeader("X-Request-ID"), c.GetHeader("X-Correlation-ID")),
|
||||
Comment: "Copilot provider configuration updated",
|
||||
}
|
||||
if accountID := c.GetUint("account_id"); accountID != 0 {
|
||||
audit.AccountID = &accountID
|
||||
audit.AssociatedType = "Account"
|
||||
audit.AssociatedID = &accountID
|
||||
}
|
||||
if userID := getUserID(c); userID != 0 {
|
||||
audit.UserID = &userID
|
||||
audit.UserType = "SuperAdmin"
|
||||
}
|
||||
if _, err := h.audit.CreateAudit(c.Request.Context(), audit); err != nil {
|
||||
applogger.L().Warnf("Copilot provider audit skipped: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) PlatformTest(c *gin.Context) {
|
||||
var input service.CopilotProviderConfigInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
@@ -55,7 +123,8 @@ func (h *CopilotConfigHandler) PlatformTest(c *gin.Context) {
|
||||
if err != nil {
|
||||
status := http.StatusUnprocessableEntity
|
||||
if errors.Is(err, llm.ErrProviderNotConfigured) {
|
||||
status = http.StatusConflict
|
||||
response.AbortWithStatusError(c, http.StatusConflict, response.ErrCopilotNotConfigured, err.Error())
|
||||
return
|
||||
}
|
||||
c.JSON(status, gin.H{"error": err.Error()})
|
||||
return
|
||||
@@ -63,6 +132,31 @@ func (h *CopilotConfigHandler) PlatformTest(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, payload)
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) PlatformEmbeddingReindexStatus(c *gin.Context) {
|
||||
if h.articles == nil {
|
||||
response.AbortWithStatusError(c, http.StatusServiceUnavailable, response.ErrServiceUnavail, "embedding reindex is not configured")
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, h.articles.EmbeddingReindexStatus())
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) PlatformEmbeddingReindexStart(c *gin.Context) {
|
||||
if h.articles == nil {
|
||||
response.AbortWithStatusError(c, http.StatusServiceUnavailable, response.ErrServiceUnavail, "embedding reindex is not configured")
|
||||
return
|
||||
}
|
||||
status, err := h.articles.StartEmbeddingReindex()
|
||||
if err != nil {
|
||||
code := http.StatusUnprocessableEntity
|
||||
if status.Running {
|
||||
code = http.StatusConflict
|
||||
}
|
||||
c.JSON(code, gin.H{"error": err.Error(), "status": status})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusAccepted, status)
|
||||
}
|
||||
|
||||
func (h *CopilotConfigHandler) AccountGet(c *gin.Context) {
|
||||
if !captainPreferencesCanUpdate(c) {
|
||||
response.AbortWithStatusError(c, http.StatusForbidden, response.ErrForbidden, "administrator role required")
|
||||
|
||||
Reference in New Issue
Block a user