init: initial commit

This commit is contained in:
Blizzard
2026-04-01 14:09:33 +08:00
commit aef2e152dc
66 changed files with 6540 additions and 0 deletions
+131
View File
@@ -0,0 +1,131 @@
package service
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
"AI-Expert-Sidebar/internal/database"
"AI-Expert-Sidebar/internal/models"
)
// ListLibraries returns all registered knowledge libraries with entry counts.
func ListLibraries() ([]models.Library, error) {
sdb := database.GetSettings()
if sdb == nil {
return nil, fmt.Errorf("settings DB not ready")
}
var libs []models.Library
if err := sdb.Order("created_at asc").Find(&libs).Error; err != nil {
return nil, err
}
// Populate entry count for each library
for i, lib := range libs {
libs[i].EntryCount = countEntries(lib.FilePath)
}
return libs, nil
}
// CreateLibrary registers a new knowledge library and creates its SQLite file.
func CreateLibrary(name, description string) (*models.Library, error) {
sdb := database.GetSettings()
dir := database.DataDir
fileName := sanitizeFileName(name) + ".db"
filePath := filepath.Join(dir, fileName)
// Ensure uniqueness of file path
if _, err := os.Stat(filePath); err == nil {
filePath = filepath.Join(dir, sanitizeFileName(name)+"_"+fmt.Sprintf("%d", time.Now().Unix())+".db")
}
if err := database.NewLibraryDB(filePath); err != nil {
return nil, fmt.Errorf("create library DB: %w", err)
}
lib := models.Library{Name: name, Description: description, FilePath: filePath}
if err := sdb.Create(&lib).Error; err != nil {
os.Remove(filePath) // rollback file
return nil, err
}
log.Printf("[Library] Created: %s → %s", name, filePath)
return &lib, nil
}
// SwitchLibrary makes the named library active.
func SwitchLibrary(name string) error {
sdb := database.GetSettings()
var lib models.Library
if err := sdb.Where("name = ?", name).First(&lib).Error; err != nil {
return fmt.Errorf("library %q not found", name)
}
return database.OpenLibrary(lib)
}
// DeleteLibrary removes a library from the registry (and optionally its file).
func DeleteLibrary(name string, deleteFile bool) error {
sdb := database.GetSettings()
var lib models.Library
if err := sdb.Where("name = ?", name).First(&lib).Error; err != nil {
return fmt.Errorf("library %q not found", name)
}
if err := sdb.Delete(&lib).Error; err != nil {
return err
}
if deleteFile {
return os.Remove(lib.FilePath)
}
return nil
}
// InitLibraries restores the last active library or creates the default one.
func InitLibraries() error {
sdb := database.GetSettings()
// Check active_library preference
var setting models.AppSetting
if sdb.Where("key = ?", "active_library").First(&setting).Error == nil {
if err := SwitchLibrary(setting.Value); err == nil {
return nil // restored successfully
}
}
// No preference or stale — find first library
var lib models.Library
if sdb.Order("created_at asc").First(&lib).Error == nil {
return database.OpenLibrary(lib)
}
// No libraries at all — create default
lib2, err := CreateLibrary("默认知识库", "自动创建的默认知识库")
if err != nil {
return err
}
return database.OpenLibrary(*lib2)
}
// ── helpers ───────────────────────────────────────────────────────────────────
func countEntries(filePath string) int {
db, err := database.NewLibraryDBReadOnly(filePath)
if err != nil {
return -1
}
var count int64
db.Model(&models.Entry{}).Count(&count)
return int(count)
}
func sanitizeFileName(name string) string {
result := make([]rune, 0, len(name))
for _, r := range name {
if r == '/' || r == '\\' || r == ':' || r == '*' || r == '?' || r == '"' || r == '<' || r == '>' || r == '|' {
result = append(result, '_')
} else {
result = append(result, r)
}
}
if len(result) == 0 {
return "library"
}
return string(result)
}