Ariver
2026-06-24 a5adc6d1d88cadeead81b79fd270501c243524c7
privatevoice.src/services/engine_service.go
@@ -16,16 +16,20 @@
// EngineService provides engine status and model management to the frontend.
type EngineService struct {
   cfg            *config.Config
   app            *application.App
   initCallback   func()
   mu             sync.RWMutex
   status         string
   hardwareInfo   string
   lastError      string
   downloadMu     sync.Mutex
   downloadID     string
   downloadCancel context.CancelFunc
   cfg                *config.Config
   app                *application.App
   initCallback       func()
   mu                 sync.RWMutex
   status             string
   hardwareInfo       string
   lastError          string
   downloadMu         sync.Mutex
   downloadID         string
   downloadCancel     context.CancelFunc
   downloadCancelling bool
   downloadProgress   float64
   downloadDownloaded int64
   downloadTotal      int64
}
func NewEngineService(cfg *config.Config) *EngineService {
@@ -117,6 +121,7 @@
   defer finish()
   err = model.DownloadProfileWithContext(ctx, profile, profile.DownloadURLs, paths.ModelsRoot(), func(percent float64, downloaded, total int64) {
      s.updateModelDownloadProgress(profile.ID, percent, downloaded, total)
      if s.app != nil {
         s.app.Event.Emit("model:download-progress", map[string]interface{}{
            "percent":    percent,
@@ -145,6 +150,7 @@
      s.downloadMu.Unlock()
      return false
   }
   s.downloadCancelling = true
   s.downloadCancel()
   s.downloadMu.Unlock()
@@ -154,6 +160,12 @@
      })
   }
   return true
}
func (s *EngineService) GetModelDownloadStatus() map[string]interface{} {
   s.downloadMu.Lock()
   defer s.downloadMu.Unlock()
   return s.modelDownloadStatusLocked()
}
func (s *EngineService) modelStatusMap(profile model.ModelProfile, current modelselection.CurrentModel) map[string]interface{} {
@@ -215,6 +227,7 @@
   defer finish()
   err = model.DownloadProfileWithContext(ctx, profile, []string{primaryURL, fallbackURL}, paths.ModelsRoot(), func(percent float64, downloaded, total int64) {
      s.updateModelDownloadProgress(profile.ID, percent, downloaded, total)
      if s.app != nil {
         s.app.Event.Emit("model:download-progress", map[string]interface{}{
            "percent":    percent,
@@ -248,6 +261,7 @@
   defer finish()
   err = model.DownloadProfileWithContext(ctx, current.Profile, current.Profile.DownloadURLs, paths.ModelsRoot(), func(percent float64, downloaded, total int64) {
      s.updateModelDownloadProgress(current.ModelID, percent, downloaded, total)
      if s.app != nil {
         s.app.Event.Emit("model:download-progress", map[string]interface{}{
            "percent":    percent,
@@ -304,17 +318,53 @@
   ctx, cancel := context.WithCancel(context.Background())
   s.downloadID = modelID
   s.downloadCancel = cancel
   s.downloadCancelling = false
   s.downloadProgress = 0
   s.downloadDownloaded = 0
   s.downloadTotal = 0
   finish := func() {
      emitFinished := false
      s.downloadMu.Lock()
      if s.downloadID == modelID {
         s.downloadID = ""
         s.downloadCancel = nil
         s.downloadCancelling = false
         s.downloadProgress = 0
         s.downloadDownloaded = 0
         s.downloadTotal = 0
         emitFinished = true
      }
      s.downloadMu.Unlock()
      if emitFinished && s.app != nil {
         s.app.Event.Emit("model:download-finished", map[string]interface{}{
            "modelID": modelID,
         })
      }
   }
   return ctx, finish, nil
}
func (s *EngineService) updateModelDownloadProgress(modelID string, percent float64, downloaded, total int64) {
   s.downloadMu.Lock()
   if s.downloadID == modelID && s.downloadCancel != nil {
      s.downloadProgress = percent
      s.downloadDownloaded = downloaded
      s.downloadTotal = total
   }
   s.downloadMu.Unlock()
}
func (s *EngineService) modelDownloadStatusLocked() map[string]interface{} {
   return map[string]interface{}{
      "active":     s.downloadCancel != nil,
      "modelID":    s.downloadID,
      "cancelling": s.downloadCancelling,
      "percent":    s.downloadProgress,
      "downloaded": s.downloadDownloaded,
      "total":      s.downloadTotal,
   }
}
func (s *EngineService) allowedModelProfile(modelID string) (model.ModelProfile, error) {
   profile, err := model.GetModelProfile(modelID)
   if err != nil {