feat(admin): 添加提示词批量删除和定时同步功能
- 后端新增批量删除提示词接口和实现 - 前端管理页面添加多选和批量删除功能 - 添加定时同步GitHub远程提示词源功能 - 新增系统设置中的提示词同步配置选项 - 更新文档说明新的批量操作和定时同步功能 - 添加相关的测试用例和依赖库
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/basketikun/infinite-canvas/model"
|
||||
"github.com/basketikun/infinite-canvas/repository"
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
const defaultPromptSyncCron = "0 3 * * *"
|
||||
|
||||
var (
|
||||
promptSyncCron *cron.Cron
|
||||
promptSyncOnce sync.Once
|
||||
promptSyncMu sync.Mutex
|
||||
)
|
||||
|
||||
func StartPromptSyncScheduler() {
|
||||
promptSyncOnce.Do(func() {
|
||||
promptSyncCron = cron.New()
|
||||
promptSyncCron.Start()
|
||||
})
|
||||
RefreshPromptSyncScheduler()
|
||||
}
|
||||
|
||||
func RefreshPromptSyncScheduler() {
|
||||
promptSyncMu.Lock()
|
||||
defer promptSyncMu.Unlock()
|
||||
if promptSyncCron == nil {
|
||||
return
|
||||
}
|
||||
for _, entry := range promptSyncCron.Entries() {
|
||||
promptSyncCron.Remove(entry.ID)
|
||||
}
|
||||
settings, err := repository.GetSettings()
|
||||
if err != nil {
|
||||
log.Printf("load prompt sync setting failed err=%v", err)
|
||||
return
|
||||
}
|
||||
setting := normalizePromptSyncSetting(settings.Private.PromptSync)
|
||||
if !setting.Enabled {
|
||||
return
|
||||
}
|
||||
if _, err := promptSyncCron.AddFunc(setting.Cron, SyncRemotePromptCategories); err != nil {
|
||||
log.Printf("add prompt sync cron failed cron=%s err=%v", setting.Cron, err)
|
||||
}
|
||||
}
|
||||
|
||||
func SyncRemotePromptCategories() {
|
||||
for _, category := range repository.PromptCategories() {
|
||||
if !category.Remote {
|
||||
continue
|
||||
}
|
||||
log.Printf("scheduled prompt sync start category=%s", category.Category)
|
||||
if _, err := SyncPromptCategory(category.Category); err != nil {
|
||||
log.Printf("scheduled prompt sync failed category=%s err=%v", category.Category, err)
|
||||
continue
|
||||
}
|
||||
log.Printf("scheduled prompt sync done category=%s", category.Category)
|
||||
}
|
||||
}
|
||||
|
||||
func normalizePromptSyncSetting(setting model.PromptSyncSetting) model.PromptSyncSetting {
|
||||
if setting.Cron == "" {
|
||||
setting.Cron = defaultPromptSyncCron
|
||||
}
|
||||
return setting
|
||||
}
|
||||
@@ -48,6 +48,13 @@ func DeletePrompt(id string) error {
|
||||
return repository.DeletePrompt(id)
|
||||
}
|
||||
|
||||
func DeletePrompts(ids []string) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
return repository.DeletePrompts(ids)
|
||||
}
|
||||
|
||||
func promptCategoryCodes(items []model.PromptCategory) []string {
|
||||
codes := []string{}
|
||||
for _, item := range items {
|
||||
|
||||
@@ -32,6 +32,9 @@ func SaveSettings(settings model.Settings) (model.Settings, error) {
|
||||
settings = normalizeSettings(settings)
|
||||
keepPrivateAPIKeys(&settings, normalizeSettings(saved))
|
||||
result, err := repository.SaveSettings(settings, now())
|
||||
if err == nil {
|
||||
RefreshPromptSyncScheduler()
|
||||
}
|
||||
return hidePrivateAPIKeys(result), err
|
||||
}
|
||||
|
||||
@@ -72,6 +75,7 @@ func normalizePrivateSetting(setting model.PrivateSetting) model.PrivateSetting
|
||||
if setting.Channels == nil {
|
||||
setting.Channels = []model.ModelChannel{}
|
||||
}
|
||||
setting.PromptSync = normalizePromptSyncSetting(setting.PromptSync)
|
||||
for i := range setting.Channels {
|
||||
if setting.Channels[i].Protocol == "" {
|
||||
setting.Channels[i].Protocol = "openai"
|
||||
|
||||
Reference in New Issue
Block a user