package model
|
|
import (
|
"encoding/json"
|
"os"
|
"path/filepath"
|
"time"
|
|
"voicesnap/internal/paths"
|
)
|
|
type InstallState struct {
|
SchemaVersion int `json:"schemaVersion"`
|
SelectedModelID string `json:"selectedModelId"`
|
InstalledModels map[string]InstalledModelState `json:"installedModels"`
|
}
|
|
type InstalledModelState struct {
|
InstalledAt int64 `json:"installedAt"`
|
Version string `json:"version"`
|
Path string `json:"path"`
|
SourceDirKind string `json:"sourceDirKind"`
|
}
|
|
func NewInstallState() *InstallState {
|
return &InstallState{
|
SchemaVersion: 1,
|
SelectedModelID: DefaultModelID,
|
InstalledModels: make(map[string]InstalledModelState),
|
}
|
}
|
|
func LoadInstallState() (*InstallState, error) {
|
return LoadInstallStateFromRoot(paths.ModelsRoot())
|
}
|
|
func LoadInstallStateFromRoot(modelsRoot string) (*InstallState, error) {
|
data, err := os.ReadFile(filepath.Join(modelsRoot, "state.json"))
|
if err != nil {
|
if os.IsNotExist(err) {
|
return NewInstallState(), nil
|
}
|
return NewInstallState(), err
|
}
|
|
state := NewInstallState()
|
if err := json.Unmarshal(data, state); err != nil {
|
return NewInstallState(), err
|
}
|
normalizeInstallState(state)
|
return state, nil
|
}
|
|
func SaveInstallState(state *InstallState) error {
|
return SaveInstallStateToRoot(paths.ModelsRoot(), state)
|
}
|
|
func SaveInstallStateToRoot(modelsRoot string, state *InstallState) error {
|
normalizeInstallState(state)
|
if err := os.MkdirAll(modelsRoot, 0755); err != nil {
|
return err
|
}
|
|
data, err := json.MarshalIndent(state, "", " ")
|
if err != nil {
|
return err
|
}
|
|
target := filepath.Join(modelsRoot, "state.json")
|
tmp := target + ".tmp"
|
if err := os.WriteFile(tmp, data, 0644); err != nil {
|
return err
|
}
|
return os.Rename(tmp, target)
|
}
|
|
func UpdateInstalledModelState(modelsRoot string, profile ModelProfile, relPath, sourceDirKind string) error {
|
state, _ := LoadInstallStateFromRoot(modelsRoot)
|
state.SelectedModelID = profile.ID
|
state.InstalledModels[profile.ID] = InstalledModelState{
|
InstalledAt: time.Now().UnixMilli(),
|
Version: "unknown",
|
Path: relPath,
|
SourceDirKind: sourceDirKind,
|
}
|
return SaveInstallStateToRoot(modelsRoot, state)
|
}
|
|
func normalizeInstallState(state *InstallState) {
|
if state.SchemaVersion == 0 {
|
state.SchemaVersion = 1
|
}
|
state.SelectedModelID = NormalizeModelID(state.SelectedModelID)
|
if state.InstalledModels == nil {
|
state.InstalledModels = make(map[string]InstalledModelState)
|
}
|
}
|