init: initial commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"AI-Expert-Sidebar/internal/config"
|
||||
"AI-Expert-Sidebar/internal/crypto"
|
||||
"AI-Expert-Sidebar/internal/database"
|
||||
"AI-Expert-Sidebar/internal/models"
|
||||
)
|
||||
|
||||
// SettingsDTO is what the frontend reads and writes.
|
||||
type SettingsDTO struct {
|
||||
AIProvider string `json:"ai_provider"`
|
||||
BaseURL string `json:"base_url"`
|
||||
APIKey string `json:"api_key"`
|
||||
Model string `json:"model"`
|
||||
SystemPrompt string `json:"system_prompt"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
UsePublicKey bool `json:"use_public_key"`
|
||||
}
|
||||
|
||||
// GetSettings reads AI config from settings.db key-value store.
|
||||
func GetSettings() *SettingsDTO {
|
||||
sdb := database.GetSettings()
|
||||
if sdb == nil {
|
||||
return defaultDTO()
|
||||
}
|
||||
var rows []models.AppSetting
|
||||
sdb.Find(&rows)
|
||||
m := make(map[string]string, len(rows))
|
||||
for _, r := range rows {
|
||||
m[r.Key] = r.Value
|
||||
}
|
||||
|
||||
apiKey, _ := crypto.DecryptAPIKey(m["api_key_encrypted"])
|
||||
maxTokens := 1024
|
||||
fmt.Sscanf(m["max_tokens"], "%d", &maxTokens)
|
||||
if maxTokens <= 0 {
|
||||
maxTokens = 1024
|
||||
}
|
||||
return &SettingsDTO{
|
||||
AIProvider: strOr(m["ai_provider"], "deepseek"),
|
||||
BaseURL: m["base_url"],
|
||||
APIKey: apiKey,
|
||||
Model: strOr(m["model"], "deepseek-chat"),
|
||||
SystemPrompt: m["system_prompt"],
|
||||
MaxTokens: maxTokens,
|
||||
UsePublicKey: m["use_public_key"] != "false",
|
||||
}
|
||||
}
|
||||
|
||||
// SaveSettings persists AI config into settings.db.
|
||||
func SaveSettings(dto SettingsDTO) error {
|
||||
sdb := database.GetSettings()
|
||||
if sdb == nil {
|
||||
return fmt.Errorf("settings DB not ready")
|
||||
}
|
||||
upsert := func(k, v string) {
|
||||
sdb.Exec("INSERT INTO app_settings(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value", k, v)
|
||||
}
|
||||
upsert("ai_provider", dto.AIProvider)
|
||||
upsert("base_url", dto.BaseURL)
|
||||
upsert("model", dto.Model)
|
||||
upsert("system_prompt", dto.SystemPrompt)
|
||||
upsert("max_tokens", fmt.Sprintf("%d", dto.MaxTokens))
|
||||
usePublic := "true"
|
||||
if !dto.UsePublicKey {
|
||||
usePublic = "false"
|
||||
}
|
||||
upsert("use_public_key", usePublic)
|
||||
if !dto.UsePublicKey && dto.APIKey != "" {
|
||||
enc, err := crypto.EncryptAPIKey(dto.APIKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upsert("api_key_encrypted", enc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveAIConfig returns the effective AI call config (local settings or global fallback).
|
||||
func ResolveAIConfig() AICallConfig {
|
||||
base := AICallConfig{
|
||||
BaseURL: "https://api.deepseek.com/chat/completions",
|
||||
APIKey: config.Global.DeepSeek.APIKey,
|
||||
Model: config.Global.DeepSeek.Model,
|
||||
MaxTokens: config.Global.DeepSeek.MaxTokens,
|
||||
}
|
||||
dto := GetSettings()
|
||||
if dto == nil {
|
||||
return base
|
||||
}
|
||||
base.SystemPrompt = dto.SystemPrompt
|
||||
if dto.UsePublicKey || dto.APIKey == "" {
|
||||
return base
|
||||
}
|
||||
providerURL := dto.BaseURL
|
||||
if providerURL == "" {
|
||||
switch dto.AIProvider {
|
||||
case "deepseek":
|
||||
providerURL = "https://api.deepseek.com/chat/completions"
|
||||
case "openai":
|
||||
providerURL = "https://api.openai.com/v1/chat/completions"
|
||||
case "grok":
|
||||
providerURL = "https://api.x.ai/v1/chat/completions"
|
||||
}
|
||||
}
|
||||
maxTok := dto.MaxTokens
|
||||
if maxTok <= 0 {
|
||||
maxTok = 1024
|
||||
}
|
||||
return AICallConfig{
|
||||
BaseURL: strOr(providerURL, base.BaseURL),
|
||||
APIKey: dto.APIKey,
|
||||
Model: strOr(dto.Model, base.Model),
|
||||
MaxTokens: maxTok,
|
||||
SystemPrompt: dto.SystemPrompt,
|
||||
}
|
||||
}
|
||||
|
||||
func strOr(v, def string) string {
|
||||
if v == "" {
|
||||
return def
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func defaultDTO() *SettingsDTO {
|
||||
return &SettingsDTO{AIProvider: "deepseek", Model: "deepseek-chat", MaxTokens: 1024, UsePublicKey: true}
|
||||
}
|
||||
Reference in New Issue
Block a user