diff --git a/api/core/config.go b/api/core/config.go
index 4d4699f4..a9032d9c 100644
--- a/api/core/config.go
+++ b/api/core/config.go
@@ -148,14 +148,24 @@ func LoadSystemConfig(db *gorm.DB) *types.SystemConfig {
logger.Error("load payment config error: ", err)
}
+ // 加载文本审查配置
+ var moderationConfig types.ModerationConfig
+ sysConfig.Id = 0
+ db.Where("name", types.ConfigKeyModeration).First(&sysConfig)
+ err = utils.JsonDecode(sysConfig.Value, &moderationConfig)
+ if err != nil {
+ logger.Error("load moderation config error: ", err)
+ }
+
return &types.SystemConfig{
- Base: baseConfig,
- License: license,
- SMS: smsConfig,
- OSS: ossConfig,
- SMTP: smtpConfig,
- Payment: paymentConfig,
- Captcha: captchaConfig,
- WxLogin: wxLoginConfig,
+ Base: baseConfig,
+ License: license,
+ SMS: smsConfig,
+ OSS: ossConfig,
+ SMTP: smtpConfig,
+ Payment: paymentConfig,
+ Captcha: captchaConfig,
+ WxLogin: wxLoginConfig,
+ Moderation: moderationConfig,
}
}
diff --git a/api/core/types/config.go b/api/core/types/config.go
index 10edddbb..9c903b8c 100644
--- a/api/core/types/config.go
+++ b/api/core/types/config.go
@@ -100,29 +100,31 @@ type BaseConfig struct {
}
type SystemConfig struct {
- Base BaseConfig
- Payment PaymentConfig
- OSS OSSConfig
- SMS SMSConfig
- SMTP SmtpConfig
- Captcha CaptchaConfig
- WxLogin WxLoginConfig
- Jimeng JimengConfig
- License License
+ Base BaseConfig
+ Payment PaymentConfig
+ OSS OSSConfig
+ SMS SMSConfig
+ SMTP SmtpConfig
+ Captcha CaptchaConfig
+ WxLogin WxLoginConfig
+ Jimeng JimengConfig
+ License License
+ Moderation ModerationConfig
}
// 配置键名常量
const (
- ConfigKeySystem = "system"
- ConfigKeyNotice = "notice"
- ConfigKeyAgreement = "agreement"
- ConfigKeyPrivacy = "privacy"
- ConfigKeyMarkMap = "mark_map"
- ConfigKeyCaptcha = "captcha"
- ConfigKeyWxLogin = "wx_login"
- ConfigKeyLicense = "license"
- ConfigKeySms = "sms"
- ConfigKeySmtp = "smtp"
- ConfigKeyOss = "oss"
- ConfigKeyPayment = "payment"
+ ConfigKeySystem = "system"
+ ConfigKeyNotice = "notice"
+ ConfigKeyAgreement = "agreement"
+ ConfigKeyPrivacy = "privacy"
+ ConfigKeyMarkMap = "mark_map"
+ ConfigKeyCaptcha = "captcha"
+ ConfigKeyWxLogin = "wx_login"
+ ConfigKeyLicense = "license"
+ ConfigKeySms = "sms"
+ ConfigKeySmtp = "smtp"
+ ConfigKeyOss = "oss"
+ ConfigKeyPayment = "payment"
+ ConfigKeyModeration = "moderation"
)
diff --git a/api/core/types/moderation.go b/api/core/types/moderation.go
new file mode 100644
index 00000000..835c9224
--- /dev/null
+++ b/api/core/types/moderation.go
@@ -0,0 +1,55 @@
+package types
+
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// * Copyright 2023 The Geek-AI Authors. All rights reserved.
+// * Use of this source code is governed by a Apache-2.0 license
+// * that can be found in the LICENSE file.
+// * @Author yangjian102621@163.com
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+// 文本审查
+type ModerationConfig struct {
+ Enable bool `json:"enable"` // 是否启用文本审查
+ Active string `json:"active"`
+ GuidePrompt string `json:"guide_prompt"` // 模型引导提示词
+ Gitee ModerationGiteeConfig `json:"gitee"`
+ Baidu ModerationBaiduConfig `json:"baidu"`
+ Tencent ModerationTencentConfig `json:"tencent"`
+}
+
+const (
+ ModerationGitee = "gitee"
+ ModerationBaidu = "baidu"
+ ModerationTencent = "tencent"
+)
+
+// GiteeAI 文本审查配置
+type ModerationGiteeConfig struct {
+ ApiKey string `json:"api_key"`
+ Model string `json:"model"` // 文本审核模型
+}
+
+// 百度文本审查配置
+type ModerationBaiduConfig struct {
+ AccessKey string `json:"access_key"`
+ SecretKey string `json:"secret_key"`
+}
+
+// 腾讯云文本审查配置
+type ModerationTencentConfig struct {
+ AccessKey string `json:"access_key"`
+ SecretKey string `json:"secret_key"`
+}
+
+type ModerationResult struct {
+ Flagged bool `json:"flagged"`
+ Categories map[string]bool `json:"categories"`
+ CategoryScores map[string]float64 `json:"category_scores"`
+}
+
+var ModerationCategories = map[string]string{
+ "politic": "内容涉及人物、事件或敏感的政治观点",
+ "porn": "明确的色情内容",
+ "insult": "具有侮辱、攻击性语言、人身攻击或冒犯性表达",
+ "violence": "包含暴力、血腥、攻击行为或煽动暴力的言论",
+}
diff --git a/api/handler/admin/config_handler.go b/api/handler/admin/config_handler.go
index baa6daab..48cfd34c 100644
--- a/api/handler/admin/config_handler.go
+++ b/api/handler/admin/config_handler.go
@@ -8,11 +8,13 @@ package admin
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import (
+ "fmt"
"geekai/core"
"geekai/core/middleware"
"geekai/core/types"
"geekai/handler"
"geekai/service"
+ "geekai/service/moderation"
"geekai/service/oss"
"geekai/service/payment"
"geekai/service/sms"
@@ -26,21 +28,17 @@ import (
type ConfigHandler struct {
handler.BaseHandler
- licenseService *service.LicenseService
- sysConfig *types.SystemConfig
- alipayService *payment.AlipayService
- wxpayService *payment.WxPayService
- epayService *payment.EPayService
- smsAliyun *sms.AliYunSmsService
- smsBao *sms.BaoSmsService
- smsManager *sms.SmsManager
- localOss *oss.LocalStorage
- qiniuOss *oss.QiNiuOss
- aliyunOss *oss.AliYunOss
- minioOss *oss.MiniOss
- smtpService *service.SmtpService
- captchaService *service.CaptchaService
- wxLoginService *service.WxLoginService
+ licenseService *service.LicenseService
+ sysConfig *types.SystemConfig
+ alipayService *payment.AlipayService
+ wxpayService *payment.WxPayService
+ epayService *payment.EPayService
+ smsManager *sms.SmsManager
+ uploaderManager *oss.UploaderManager
+ smtpService *service.SmtpService
+ captchaService *service.CaptchaService
+ wxLoginService *service.WxLoginService
+ moderationManager *moderation.ServiceManager
}
func NewConfigHandler(
@@ -51,34 +49,26 @@ func NewConfigHandler(
alipayService *payment.AlipayService,
wxpayService *payment.WxPayService,
epayService *payment.EPayService,
- smsAliyun *sms.AliYunSmsService,
- smsBao *sms.BaoSmsService,
smsManager *sms.SmsManager,
- localOss *oss.LocalStorage,
- qiniuOss *oss.QiNiuOss,
- aliyunOss *oss.AliYunOss,
- minioOss *oss.MiniOss,
+ uploaderManager *oss.UploaderManager,
smtpService *service.SmtpService,
captchaService *service.CaptchaService,
wxLoginService *service.WxLoginService,
+ moderationManager *moderation.ServiceManager,
) *ConfigHandler {
return &ConfigHandler{
- BaseHandler: handler.BaseHandler{App: app, DB: db},
- licenseService: licenseService,
- sysConfig: sysConfig,
- alipayService: alipayService,
- wxpayService: wxpayService,
- epayService: epayService,
- smsAliyun: smsAliyun,
- smsBao: smsBao,
- smsManager: smsManager,
- localOss: localOss,
- qiniuOss: qiniuOss,
- aliyunOss: aliyunOss,
- minioOss: minioOss,
- smtpService: smtpService,
- captchaService: captchaService,
- wxLoginService: wxLoginService,
+ BaseHandler: handler.BaseHandler{App: app, DB: db},
+ licenseService: licenseService,
+ sysConfig: sysConfig,
+ alipayService: alipayService,
+ wxpayService: wxpayService,
+ epayService: epayService,
+ smsManager: smsManager,
+ uploaderManager: uploaderManager,
+ moderationManager: moderationManager,
+ smtpService: smtpService,
+ captchaService: captchaService,
+ wxLoginService: wxLoginService,
}
}
@@ -101,6 +91,8 @@ func (h *ConfigHandler) RegisterRoutes() {
rg.POST("update/sms", h.UpdateSms)
rg.POST("update/oss", h.UpdateOss)
rg.POST("update/smtp", h.UpdateStmp)
+ rg.POST("update/moderation", h.UpdateModeration)
+ rg.POST("moderation/test", h.TestModeration)
rg.GET("get", h.Get)
rg.POST("license/active", h.Active)
rg.GET("license/get", h.GetLicense)
@@ -280,14 +272,7 @@ func (h *ConfigHandler) UpdatePayment(c *gin.Context) {
return
}
- var config model.Config
- oldData := types.PaymentConfig{}
- err := h.DB.Where("name", types.ConfigKeyPayment).First(&config).Error
- if err == nil {
- utils.JsonDecode(config.Value, &oldData)
- }
-
- err = h.Update(types.ConfigKeyPayment, data)
+ err := h.Update(types.ConfigKeyPayment, data)
if err != nil {
resp.ERROR(c, err.Error())
return
@@ -324,32 +309,14 @@ func (h *ConfigHandler) UpdateSms(c *gin.Context) {
return
}
- var config model.Config
- oldData := types.SMSConfig{}
- err := h.DB.Where("name", types.ConfigKeySms).First(&config).Error
- if err == nil {
- utils.JsonDecode(config.Value, &oldData)
- }
-
- err = h.Update(types.ConfigKeySms, data)
+ err := h.Update(types.ConfigKeySms, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
// 更新服务配置
- switch data.Active {
- case sms.Ali:
- err = h.smsAliyun.UpdateConfig(&data.Ali)
- if err != nil {
- resp.ERROR(c, err.Error())
- return
- }
- case sms.Bao:
- h.smsBao.UpdateConfig(&data.Bao)
- }
-
- h.smsManager.SetActive(data.Active)
+ h.smsManager.UpdateConfig(data)
resp.SUCCESS(c, data)
}
@@ -362,39 +329,14 @@ func (h *ConfigHandler) UpdateOss(c *gin.Context) {
return
}
- var config model.Config
- oldData := types.OSSConfig{}
- err := h.DB.Where("name", types.ConfigKeyOss).First(&config).Error
- if err == nil {
- utils.JsonDecode(config.Value, &oldData)
- }
-
- err = h.Update("oss", data)
+ err := h.Update(types.ConfigKeyOss, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
// 更新服务配置
- switch data.Active {
- case oss.Local:
- h.localOss.UpdateConfig(&data.Local)
- case oss.QiNiu:
- h.qiniuOss.UpdateConfig(&data.QiNiu)
- case oss.AliYun:
- err := h.aliyunOss.UpdateConfig(&data.AliYun)
- if err != nil {
- resp.ERROR(c, err.Error())
- return
- }
- case oss.Minio:
- err := h.minioOss.UpdateConfig(&data.Minio)
- if err != nil {
- resp.ERROR(c, err.Error())
- return
- }
- }
-
+ h.uploaderManager.UpdateConfig(data)
h.sysConfig.OSS = data
resp.SUCCESS(c, data)
@@ -408,24 +350,14 @@ func (h *ConfigHandler) UpdateStmp(c *gin.Context) {
return
}
- var config model.Config
- oldData := types.SmtpConfig{}
- err := h.DB.Where("name", types.ConfigKeySmtp).First(&config).Error
- if err == nil {
- utils.JsonDecode(config.Value, &oldData)
- }
-
- err = h.Update(types.ConfigKeySmtp, data)
+ err := h.Update(types.ConfigKeySmtp, data)
if err != nil {
resp.ERROR(c, err.Error())
return
}
- // 配置发生改变时更新服务配置
- if !data.Equal(&oldData) {
- h.smtpService.UpdateConfig(&data)
- }
-
+ // 更新服务配置
+ h.smtpService.UpdateConfig(&data)
h.sysConfig.SMTP = data
resp.SUCCESS(c, data)
}
@@ -519,4 +451,89 @@ func (h *ConfigHandler) GetLicense(c *gin.Context) {
resp.SUCCESS(c, license)
}
-//
+// UpdateModeration 更新文本审查配置
+func (h *ConfigHandler) UpdateModeration(c *gin.Context) {
+ var data types.ModerationConfig
+ if err := c.ShouldBindJSON(&data); err != nil {
+ resp.ERROR(c, types.InvalidArgs)
+ return
+ }
+
+ err := h.Update(types.ConfigKeyModeration, data)
+ if err != nil {
+ resp.ERROR(c, err.Error())
+ return
+ }
+
+ h.moderationManager.UpdateConfig(data)
+ h.sysConfig.Moderation = data
+
+ resp.SUCCESS(c, data)
+}
+
+// 测试结果类型,用于前端显示
+type ModerationTestResult struct {
+ IsAbnormal bool `json:"isAbnormal"`
+ Details []ModerationTestDetail `json:"details"`
+}
+
+type ModerationTestDetail struct {
+ Category string `json:"category"`
+ Description string `json:"description"`
+ Confidence string `json:"confidence"`
+ IsCategory bool `json:"isCategory"`
+}
+
+// TestModeration 测试文本审查服务
+func (h *ConfigHandler) TestModeration(c *gin.Context) {
+ var data struct {
+ Text string `json:"text"`
+ Service string `json:"service"`
+ }
+
+ if err := c.ShouldBindJSON(&data); err != nil {
+ resp.ERROR(c, types.InvalidArgs)
+ return
+ }
+
+ if data.Text == "" {
+ resp.ERROR(c, "测试文本不能为空")
+ return
+ }
+
+ // 检查是否启用了文本审查
+ if !h.sysConfig.Moderation.Enable {
+ resp.ERROR(c, "文本审查服务未启用")
+ return
+ }
+
+ // 获取当前激活的审核服务
+ service := h.moderationManager.GetService()
+ // 执行文本审核
+ result, err := service.Moderate(data.Text)
+ if err != nil {
+ resp.ERROR(c, "审核服务调用失败: "+err.Error())
+ return
+ }
+
+ // 转换为前端需要的格式
+ testResult := ModerationTestResult{
+ IsAbnormal: result.Flagged,
+ Details: make([]ModerationTestDetail, 0),
+ }
+
+ // 构建详细信息
+ for category, description := range types.ModerationCategories {
+ score := result.CategoryScores[category]
+ isCategory := result.Categories[category]
+
+ testResult.Details = append(testResult.Details, ModerationTestDetail{
+ Category: category,
+ Description: description,
+ Confidence: fmt.Sprintf("%.2f", score),
+ IsCategory: isCategory,
+ })
+ }
+
+ resp.SUCCESS(c, testResult)
+}
diff --git a/api/main.go b/api/main.go
index 6f213700..7c308f76 100644
--- a/api/main.go
+++ b/api/main.go
@@ -19,6 +19,7 @@ import (
"geekai/service/dalle"
"geekai/service/jimeng"
"geekai/service/mj"
+ "geekai/service/moderation"
"geekai/service/oss"
"geekai/service/payment"
"geekai/service/sd"
@@ -241,6 +242,12 @@ func main() {
// 用户服务
fx.Provide(service.NewUserService),
+ // 文本审查服务
+ fx.Provide(moderation.NewGiteeAIModeration),
+ fx.Provide(moderation.NewBaiduAIModeration),
+ fx.Provide(moderation.NewTencentAIModeration),
+ fx.Provide(moderation.NewServiceManager),
+
// 注册路由
fx.Invoke(func(s *core.AppServer, h *handler.ChatAppHandler) {
h.RegisterRoutes()
diff --git a/api/service/moderation/baidu_moderation.go b/api/service/moderation/baidu_moderation.go
new file mode 100644
index 00000000..b213d469
--- /dev/null
+++ b/api/service/moderation/baidu_moderation.go
@@ -0,0 +1,33 @@
+package moderation
+
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// * Copyright 2023 The Geek-AI Authors. All rights reserved.
+// * Use of this source code is governed by a Apache-2.0 license
+// * that can be found in the LICENSE file.
+// * @Author yangjian102621@163.com
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+import (
+ "errors"
+ "geekai/core/types"
+)
+
+type BaiduAIModeration struct {
+ config types.ModerationBaiduConfig
+}
+
+func NewBaiduAIModeration(sysConfig *types.SystemConfig) *BaiduAIModeration {
+ return &BaiduAIModeration{
+ config: sysConfig.Moderation.Baidu,
+ }
+}
+
+func (s *BaiduAIModeration) UpdateConfig(config types.ModerationBaiduConfig) {
+ s.config = config
+}
+
+func (s *BaiduAIModeration) Moderate(text string) (types.ModerationResult, error) {
+ return types.ModerationResult{}, errors.New("not implemented")
+}
+
+var _ Service = (*BaiduAIModeration)(nil)
diff --git a/api/service/moderation/gitee_moderation.go b/api/service/moderation/gitee_moderation.go
new file mode 100644
index 00000000..8e7ed14c
--- /dev/null
+++ b/api/service/moderation/gitee_moderation.go
@@ -0,0 +1,58 @@
+package moderation
+
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// * Copyright 2023 The Geek-AI Authors. All rights reserved.
+// * Use of this source code is governed by a Apache-2.0 license
+// * that can be found in the LICENSE file.
+// * @Author yangjian102621@163.com
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+import (
+ "errors"
+ "geekai/core/types"
+
+ "github.com/imroc/req/v3"
+)
+
+type GiteeAIModeration struct {
+ config types.ModerationGiteeConfig
+ apiURL string
+}
+
+func NewGiteeAIModeration(sysConfig *types.SystemConfig) *GiteeAIModeration {
+ return &GiteeAIModeration{
+ config: sysConfig.Moderation.Gitee,
+ apiURL: "https://ai.gitee.com/v1/moderations",
+ }
+}
+
+func (s *GiteeAIModeration) UpdateConfig(config types.ModerationGiteeConfig) {
+ s.config = config
+}
+
+type GiteeAIModerationResult struct {
+ ID string `json:"id"`
+ Model string `json:"model"`
+ Results []types.ModerationResult `json:"results"`
+}
+
+func (s *GiteeAIModeration) Moderate(text string) (types.ModerationResult, error) {
+
+ body := map[string]any{
+ "input": text,
+ "model": s.config.Model,
+ }
+ var res GiteeAIModerationResult
+ r, err := req.C().R().SetHeader("Authorization", "Bearer "+s.config.ApiKey).SetBody(body).SetSuccessResult(&res).Post(s.apiURL)
+ if err != nil {
+ return types.ModerationResult{}, err
+ }
+
+ if r.IsErrorState() {
+ return types.ModerationResult{}, errors.New(r.String())
+ }
+
+ return res.Results[0], nil
+}
+
+var _ Service = (*GiteeAIModeration)(nil)
diff --git a/api/service/moderation/moderation_manager.go b/api/service/moderation/moderation_manager.go
new file mode 100644
index 00000000..25125a93
--- /dev/null
+++ b/api/service/moderation/moderation_manager.go
@@ -0,0 +1,58 @@
+package moderation
+
+import (
+ "geekai/core/types"
+
+ logger2 "geekai/logger"
+)
+
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// * Copyright 2023 The Geek-AI Authors. All rights reserved.
+// * Use of this source code is governed by a Apache-2.0 license
+// * that can be found in the LICENSE file.
+// * @Author yangjian102621@163.com
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+var logger = logger2.GetLogger()
+
+type Service interface {
+ Moderate(text string) (types.ModerationResult, error)
+}
+
+type ServiceManager struct {
+ gitee *GiteeAIModeration
+ baidu *BaiduAIModeration
+ tencent *TencentAIModeration
+ active string
+}
+
+func NewServiceManager(gitee *GiteeAIModeration, baidu *BaiduAIModeration, tencent *TencentAIModeration) *ServiceManager {
+ return &ServiceManager{
+ gitee: gitee,
+ baidu: baidu,
+ tencent: tencent,
+ }
+}
+
+func (s *ServiceManager) GetService() Service {
+ switch s.active {
+ case types.ModerationBaidu:
+ return s.baidu
+ case types.ModerationTencent:
+ return s.tencent
+ default:
+ return s.gitee
+ }
+}
+
+func (s *ServiceManager) UpdateConfig(config types.ModerationConfig) {
+ switch config.Active {
+ case types.ModerationGitee:
+ s.gitee.UpdateConfig(config.Gitee)
+ case types.ModerationBaidu:
+ s.baidu.UpdateConfig(config.Baidu)
+ case types.ModerationTencent:
+ s.tencent.UpdateConfig(config.Tencent)
+ }
+ s.active = config.Active
+}
diff --git a/api/service/moderation/tencent_moderation.go b/api/service/moderation/tencent_moderation.go
new file mode 100644
index 00000000..75bee579
--- /dev/null
+++ b/api/service/moderation/tencent_moderation.go
@@ -0,0 +1,33 @@
+package moderation
+
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// * Copyright 2023 The Geek-AI Authors. All rights reserved.
+// * Use of this source code is governed by a Apache-2.0 license
+// * that can be found in the LICENSE file.
+// * @Author yangjian102621@163.com
+// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+import (
+ "errors"
+ "geekai/core/types"
+)
+
+type TencentAIModeration struct {
+ config types.ModerationTencentConfig
+}
+
+func NewTencentAIModeration(sysConfig *types.SystemConfig) *TencentAIModeration {
+ return &TencentAIModeration{
+ config: sysConfig.Moderation.Tencent,
+ }
+}
+
+func (s *TencentAIModeration) UpdateConfig(config types.ModerationTencentConfig) {
+ s.config = config
+}
+
+func (s *TencentAIModeration) Moderate(text string) (types.ModerationResult, error) {
+ return types.ModerationResult{}, errors.New("not implemented")
+}
+
+var _ Service = (*TencentAIModeration)(nil)
diff --git a/api/service/oss/aliyun_oss.go b/api/service/oss/aliyun_oss.go
index 20ff31b8..8c9b6602 100644
--- a/api/service/oss/aliyun_oss.go
+++ b/api/service/oss/aliyun_oss.go
@@ -23,7 +23,7 @@ import (
)
type AliYunOss struct {
- config *types.AliYunOssConfig
+ config types.AliYunOssConfig
bucket *oss.Bucket
proxyURL string
}
@@ -33,7 +33,7 @@ func NewAliYunOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) (*A
proxyURL: appConfig.ProxyURL,
}
if sysConfig.OSS.Active == AliYun {
- err := s.UpdateConfig(&sysConfig.OSS.AliYun)
+ err := s.UpdateConfig(sysConfig.OSS.AliYun)
if err != nil {
logger.Errorf("阿里云OSS初始化失败: %v", err)
}
@@ -42,7 +42,7 @@ func NewAliYunOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) (*A
}
-func (s *AliYunOss) UpdateConfig(config *types.AliYunOssConfig) error {
+func (s *AliYunOss) UpdateConfig(config types.AliYunOssConfig) error {
client, err := oss.New(config.Endpoint, config.AccessKey, config.AccessSecret)
if err != nil {
return err
diff --git a/api/service/oss/localstorage.go b/api/service/oss/localstorage.go
index b2337e8c..5b3bef82 100644
--- a/api/service/oss/localstorage.go
+++ b/api/service/oss/localstorage.go
@@ -21,18 +21,18 @@ import (
)
type LocalStorage struct {
- config *types.LocalStorageConfig
+ config types.LocalStorageConfig
proxyURL string
}
func NewLocalStorage(sysConfig *types.SystemConfig, appConfig *types.AppConfig) *LocalStorage {
return &LocalStorage{
- config: &sysConfig.OSS.Local,
+ config: sysConfig.OSS.Local,
proxyURL: appConfig.ProxyURL,
}
}
-func (s *LocalStorage) UpdateConfig(config *types.LocalStorageConfig) {
+func (s *LocalStorage) UpdateConfig(config types.LocalStorageConfig) {
s.config = config
}
diff --git a/api/service/oss/minio_oss.go b/api/service/oss/minio_oss.go
index f7465b78..0dcebf21 100644
--- a/api/service/oss/minio_oss.go
+++ b/api/service/oss/minio_oss.go
@@ -24,7 +24,7 @@ import (
)
type MiniOss struct {
- config *types.MiniOssConfig
+ config types.MiniOssConfig
client *minio.Client
proxyURL string
}
@@ -33,7 +33,7 @@ func NewMiniOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) (*Min
s := &MiniOss{proxyURL: appConfig.ProxyURL}
if sysConfig.OSS.Active == Minio {
- err := s.UpdateConfig(&sysConfig.OSS.Minio)
+ err := s.UpdateConfig(sysConfig.OSS.Minio)
if err != nil {
logger.Errorf("MinioOSS初始化失败: %v", err)
}
@@ -41,7 +41,7 @@ func NewMiniOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) (*Min
return s, nil
}
-func (s *MiniOss) UpdateConfig(config *types.MiniOssConfig) error {
+func (s *MiniOss) UpdateConfig(config types.MiniOssConfig) error {
minioClient, err := minio.New(config.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(config.AccessKey, config.AccessSecret, ""),
Secure: config.UseSSL,
diff --git a/api/service/oss/qiniu_oss.go b/api/service/oss/qiniu_oss.go
index 3623c648..c3ded24d 100644
--- a/api/service/oss/qiniu_oss.go
+++ b/api/service/oss/qiniu_oss.go
@@ -25,7 +25,7 @@ import (
)
type QiNiuOss struct {
- config *types.QiNiuOssConfig
+ config types.QiNiuOssConfig
mac *qbox.Mac
putPolicy storage.PutPolicy
uploader *storage.FormUploader
@@ -38,12 +38,12 @@ func NewQiNiuOss(sysConfig *types.SystemConfig, appConfig *types.AppConfig) *QiN
proxyURL: appConfig.ProxyURL,
}
if sysConfig.OSS.Active == QiNiu {
- s.UpdateConfig(&sysConfig.OSS.QiNiu)
+ s.UpdateConfig(sysConfig.OSS.QiNiu)
}
return s
}
-func (s *QiNiuOss) UpdateConfig(config *types.QiNiuOssConfig) {
+func (s *QiNiuOss) UpdateConfig(config types.QiNiuOssConfig) {
zone, ok := storage.GetRegionByID(storage.RegionID(config.Zone))
if !ok {
zone = storage.ZoneHuanan
diff --git a/api/service/oss/uploader_manager.go b/api/service/oss/uploader_manager.go
index 64c05b85..2f81c937 100644
--- a/api/service/oss/uploader_manager.go
+++ b/api/service/oss/uploader_manager.go
@@ -21,7 +21,7 @@ type UploaderManager struct {
aliyun *AliYunOss
mini *MiniOss
qiniu *QiNiuOss
- config *types.OSSConfig
+ active string
}
func NewUploaderManager(sysConfig *types.SystemConfig, local *LocalStorage, aliyun *AliYunOss, mini *MiniOss, qiniu *QiNiuOss) (*UploaderManager, error) {
@@ -31,7 +31,7 @@ func NewUploaderManager(sysConfig *types.SystemConfig, local *LocalStorage, aliy
sysConfig.OSS.Active = strings.ToLower(sysConfig.OSS.Active)
return &UploaderManager{
- config: &sysConfig.OSS,
+ active: sysConfig.OSS.Active,
local: local,
aliyun: aliyun,
mini: mini,
@@ -40,7 +40,7 @@ func NewUploaderManager(sysConfig *types.SystemConfig, local *LocalStorage, aliy
}
func (m *UploaderManager) GetUploadHandler() Uploader {
- switch m.config.Active {
+ switch m.active {
case Local:
return m.local
case AliYun:
@@ -52,3 +52,17 @@ func (m *UploaderManager) GetUploadHandler() Uploader {
}
return m.local
}
+
+func (m *UploaderManager) UpdateConfig(config types.OSSConfig) {
+ switch config.Active {
+ case Local:
+ m.local.UpdateConfig(config.Local)
+ case AliYun:
+ m.aliyun.UpdateConfig(config.AliYun)
+ case Minio:
+ m.mini.UpdateConfig(config.Minio)
+ case QiNiu:
+ m.qiniu.UpdateConfig(config.QiNiu)
+ }
+ m.active = config.Active
+}
diff --git a/api/service/sms/aliyun.go b/api/service/sms/aliyun.go
index 858263dd..db9d7c4e 100644
--- a/api/service/sms/aliyun.go
+++ b/api/service/sms/aliyun.go
@@ -15,14 +15,14 @@ import (
)
type AliYunSmsService struct {
- config *types.SmsConfigAli
+ config types.SmsConfigAli
client *dysmsapi.Client
domain string
zoneId string
}
func NewAliYunSmsService(sysConfig *types.SystemConfig) (*AliYunSmsService, error) {
- config := &sysConfig.SMS.Ali
+ config := sysConfig.SMS.Ali
domain := "dysmsapi.aliyuncs.com"
zoneId := "cn-hangzhou"
@@ -40,7 +40,7 @@ func NewAliYunSmsService(sysConfig *types.SystemConfig) (*AliYunSmsService, erro
return &s, nil
}
-func (s *AliYunSmsService) UpdateConfig(config *types.SmsConfigAli) error {
+func (s *AliYunSmsService) UpdateConfig(config types.SmsConfigAli) error {
client, err := dysmsapi.NewClientWithAccessKey(
s.zoneId,
config.AccessKey,
diff --git a/api/service/sms/bao.go b/api/service/sms/bao.go
index 19a1537c..a220180d 100644
--- a/api/service/sms/bao.go
+++ b/api/service/sms/bao.go
@@ -19,18 +19,18 @@ import (
)
type BaoSmsService struct {
- config *types.SmsConfigBao
+ config types.SmsConfigBao
domain string
}
func NewBaoSmsService(sysConfig *types.SystemConfig) *BaoSmsService {
return &BaoSmsService{
- config: &sysConfig.SMS.Bao,
+ config: sysConfig.SMS.Bao,
domain: "api.smsbao.com",
}
}
-func (s *BaoSmsService) UpdateConfig(config *types.SmsConfigBao) {
+func (s *BaoSmsService) UpdateConfig(config types.SmsConfigBao) {
s.config = config
}
diff --git a/api/service/sms/service_manager.go b/api/service/sms/sms_manager.go
similarity index 76%
rename from api/service/sms/service_manager.go
rename to api/service/sms/sms_manager.go
index 3e2ac652..32921827 100644
--- a/api/service/sms/service_manager.go
+++ b/api/service/sms/sms_manager.go
@@ -30,12 +30,25 @@ func NewSmsManager(sysConfig *types.SystemConfig, aliyun *AliYunSmsService, bao
}
func (m *SmsManager) GetService() Service {
- if m.active == Ali {
+ switch m.active {
+ case Ali:
return m.aliyun
+ case Bao:
+ return m.bao
}
- return m.bao
+ return nil
}
func (m *SmsManager) SetActive(active string) {
m.active = active
}
+
+func (m *SmsManager) UpdateConfig(config types.SMSConfig) {
+ switch config.Active {
+ case Ali:
+ m.aliyun.UpdateConfig(config.Ali)
+ case Bao:
+ m.bao.UpdateConfig(config.Bao)
+ }
+ m.active = config.Active
+}
diff --git a/web/src/assets/iconfont/iconfont.css b/web/src/assets/iconfont/iconfont.css
index 72ee9c84..f8aff2db 100644
--- a/web/src/assets/iconfont/iconfont.css
+++ b/web/src/assets/iconfont/iconfont.css
@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4125778 */
- src: url('iconfont.woff2?t=1754626711656') format('woff2'),
- url('iconfont.woff?t=1754626711656') format('woff'),
- url('iconfont.ttf?t=1754626711656') format('truetype');
+ src: url('iconfont.woff2?t=1756631578371') format('woff2'),
+ url('iconfont.woff?t=1756631578371') format('woff'),
+ url('iconfont.ttf?t=1756631578371') format('truetype');
}
.iconfont {
@@ -13,6 +13,18 @@
-moz-osx-font-smoothing: grayscale;
}
+.icon-tencent:before {
+ content: "\e655";
+}
+
+.icon-baidu:before {
+ content: "\e656";
+}
+
+.icon-moderation:before {
+ content: "\e6c6";
+}
+
.icon-back-bold:before {
content: "\e654";
}
diff --git a/web/src/assets/iconfont/iconfont.js b/web/src/assets/iconfont/iconfont.js
index 53fdf836..0f79bc47 100644
--- a/web/src/assets/iconfont/iconfont.js
+++ b/web/src/assets/iconfont/iconfont.js
@@ -1 +1 @@
-window._iconfont_svg_string_4125778='',(a=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var h,t,i,o,z,m=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=h,o=a.document,z=!1,v(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,p())})}function p(){z||(z=!0,i())}function v(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(v,50)}p()}})(window);
\ No newline at end of file
+window._iconfont_svg_string_4125778='',(a=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var h,t,i,o,z,m=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4125778,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=h,o=a.document,z=!1,v(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,p())})}function p(){z||(z=!0,i())}function v(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(v,50)}p()}})(window);
\ No newline at end of file
diff --git a/web/src/assets/iconfont/iconfont.json b/web/src/assets/iconfont/iconfont.json
index 7dce4c65..d1f01f31 100644
--- a/web/src/assets/iconfont/iconfont.json
+++ b/web/src/assets/iconfont/iconfont.json
@@ -5,6 +5,27 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
+ {
+ "icon_id": "3547761",
+ "name": "tencent",
+ "font_class": "tencent",
+ "unicode": "e655",
+ "unicode_decimal": 58965
+ },
+ {
+ "icon_id": "26267540",
+ "name": "baidu",
+ "font_class": "baidu",
+ "unicode": "e656",
+ "unicode_decimal": 58966
+ },
+ {
+ "icon_id": "31975090",
+ "name": "Content Moderation",
+ "font_class": "moderation",
+ "unicode": "e6c6",
+ "unicode_decimal": 59078
+ },
{
"icon_id": "27025075",
"name": "返回",
diff --git a/web/src/assets/iconfont/iconfont.ttf b/web/src/assets/iconfont/iconfont.ttf
index f8155a03..7834ecc8 100644
Binary files a/web/src/assets/iconfont/iconfont.ttf and b/web/src/assets/iconfont/iconfont.ttf differ
diff --git a/web/src/assets/iconfont/iconfont.woff b/web/src/assets/iconfont/iconfont.woff
index 6d1cb8d9..8ed592be 100644
Binary files a/web/src/assets/iconfont/iconfont.woff and b/web/src/assets/iconfont/iconfont.woff differ
diff --git a/web/src/assets/iconfont/iconfont.woff2 b/web/src/assets/iconfont/iconfont.woff2
index 546aad3f..9d77c06d 100644
Binary files a/web/src/assets/iconfont/iconfont.woff2 and b/web/src/assets/iconfont/iconfont.woff2 differ
diff --git a/web/src/components/ChatPrompt.vue b/web/src/components/ChatPrompt.vue
index 9ab8a2c7..6fe20889 100644
--- a/web/src/components/ChatPrompt.vue
+++ b/web/src/components/ChatPrompt.vue
@@ -36,7 +36,14 @@
{{ dateFormat(data.created_at) }}
- tokens: {{ finalTokens }}
+
+
+
+
+
@@ -81,7 +88,14 @@
{{ dateFormat(data.created_at) }}
-
+
+
+
+
+
@@ -90,6 +104,7 @@