Files
infinite-canvas/repository/prompt.go
T
HouYunFei 472bf8b732 first commit
Co-Authored-By: Codex <noreply@openai.com>
2026-05-19 19:50:36 +08:00

187 lines
4.8 KiB
Go

package repository
import (
"errors"
"github.com/basketikun/infinite-canvas/model"
"gorm.io/gorm"
)
// PromptCategories 返回内置提示词分类的副本。
func PromptCategories() []model.PromptCategory {
result := make([]model.PromptCategory, len(promptCategories))
copy(result, promptCategories)
return result
}
// PromptCategoryByCode 根据分类编码查找内置提示词分类。
func PromptCategoryByCode(category string) (model.PromptCategory, bool) {
for _, item := range promptCategories {
if item.Category == category {
return item, true
}
}
return model.PromptCategory{}, false
}
// ListPromptCategories 返回内置提示词分类。
func ListPromptCategories() ([]model.PromptCategory, error) {
return PromptCategories(), nil
}
// ListPrompts 按查询条件返回提示词分页列表。
func ListPrompts(q model.Query) ([]model.Prompt, int64, error) {
db, err := DB()
if err != nil {
return nil, 0, err
}
q.Normalize()
tx := applyPromptFilters(db.Model(&model.Prompt{}), q)
var total int64
if err := tx.Count(&total).Error; err != nil {
return nil, 0, err
}
var items []model.Prompt
if err := tx.Order("updated_at desc").Offset(q.Offset()).Limit(q.PageSize).Find(&items).Error; err != nil {
return nil, 0, err
}
categories, _ := ListPromptCategories()
githubURLs := map[string]string{}
for _, item := range categories {
githubURLs[item.Category] = item.GithubURL
}
for i := range items {
items[i].GithubURL = githubURLs[items[i].Category]
}
return items, total, nil
}
// ListPromptTags 返回当前提示词查询条件下的全部标签。
func ListPromptTags(q model.Query) ([]string, error) {
db, err := DB()
if err != nil {
return nil, err
}
q.Normalize()
q.Tags = nil
tx := applyPromptFilters(db.Model(&model.Prompt{}), q)
var items []model.Prompt
if err := tx.Select("tags").Find(&items).Error; err != nil {
return nil, err
}
return promptTagsFromItems(items), nil
}
// SavePrompt 保存提示词,并在更新时保留原创建时间。
func SavePrompt(item model.Prompt) (model.Prompt, error) {
db, err := DB()
if err != nil {
return item, err
}
if saved, ok, err := findPrompt(db, item.ID); err != nil {
return item, err
} else if ok && item.CreatedAt == "" {
item.CreatedAt = saved.CreatedAt
}
item.GithubURL = ""
return item, db.Save(&item).Error
}
// DeletePrompt 删除指定提示词。
func DeletePrompt(id string) error {
db, err := DB()
if err != nil {
return err
}
return db.Delete(&model.Prompt{}, "id = ?", id).Error
}
// ReplacePromptCategory 用远程同步结果替换整个提示词分类。
func ReplacePromptCategory(category model.PromptCategory, items []model.Prompt) error {
db, err := DB()
if err != nil {
return err
}
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("category = ?", category.Category).Delete(&model.Prompt{}).Error; err != nil {
return err
}
if len(items) == 0 {
return nil
}
for i := range items {
items[i].Category = category.Category
items[i].GithubURL = ""
}
return tx.Create(&items).Error
})
}
// applyPromptFilters 应用提示词列表的搜索条件。
func applyPromptFilters(tx *gorm.DB, q model.Query) *gorm.DB {
if q.Keyword != "" {
like := "%" + q.Keyword + "%"
tx = tx.Where("title LIKE ? OR prompt LIKE ?", like, like)
}
if isActivePromptOption(q.Category) {
tx = tx.Where("category = ?", q.Category)
}
return applyPromptTagsFilter(tx, q.Tags)
}
// findPrompt 根据 ID 查询提示词。
func findPrompt(db *gorm.DB, id string) (model.Prompt, bool, error) {
item := model.Prompt{}
err := db.Where("id = ?", id).First(&item).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return model.Prompt{}, false, nil
}
return item, err == nil, err
}
// applyPromptTagsFilter 应用 JSON 标签条件。
func applyPromptTagsFilter(tx *gorm.DB, tags []string) *gorm.DB {
if len(tags) == 0 {
return tx
}
condition := tx.Session(&gorm.Session{NewDB: true})
for _, tag := range tags {
condition = condition.Or(promptJSONTagsContains(tx), tag)
}
return tx.Where(condition)
}
func promptTagsFromItems(items []model.Prompt) []string {
seen := map[string]bool{}
tags := []string{}
for _, item := range items {
for _, tag := range item.Tags {
if tag != "" && !seen[tag] {
seen[tag] = true
tags = append(tags, tag)
}
}
}
return tags
}
// promptJSONTagsContains 返回提示词 tags 的 JSON 包含条件。
func promptJSONTagsContains(tx *gorm.DB) string {
switch tx.Dialector.Name() {
case "mysql":
return "JSON_CONTAINS(tags, JSON_QUOTE(?))"
case "postgres":
return "jsonb_exists(tags::jsonb, ?)"
default:
return "EXISTS (SELECT 1 FROM json_each(tags) WHERE value = ?)"
}
}
// isActivePromptOption 判断提示词筛选项有效状态。
func isActivePromptOption(value string) bool {
return value != "" && value != "全部" && value != "all"
}