diff options
| author | Paul Buetow <paul@buetow.org> | 2025-07-16 21:44:28 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-07-16 21:44:28 +0300 |
| commit | e2e75315e5e7c3eaccdc38881bd2fa669bb9dda5 (patch) | |
| tree | c751e8c9b4d1efd858310fba54451e791c67737b /internal/gui | |
| parent | 6b0b4c9ce28b88ab0abbff03c5f367d89ba97c89 (diff) | |
only one img per card
Diffstat (limited to 'internal/gui')
| -rw-r--r-- | internal/gui/app.go | 52 | ||||
| -rw-r--r-- | internal/gui/generator.go | 32 | ||||
| -rw-r--r-- | internal/gui/navigation.go | 20 | ||||
| -rw-r--r-- | internal/gui/queue.go | 6 |
4 files changed, 53 insertions, 57 deletions
diff --git a/internal/gui/app.go b/internal/gui/app.go index 836ebca..3a8dd33 100644 --- a/internal/gui/app.go +++ b/internal/gui/app.go @@ -51,7 +51,7 @@ type Application struct { // State management currentWord string currentAudioFile string - currentImages []string + currentImage string currentTranslation string currentJobID int savedCards []anki.Card @@ -81,7 +81,6 @@ type Config struct { OutputDir string AudioFormat string ImageProvider string - ImagesPerWord int EnableCache bool OpenAIKey string PixabayKey string @@ -94,7 +93,6 @@ func DefaultConfig() *Config { OutputDir: "./anki_cards", AudioFormat: "mp3", ImageProvider: "openai", - ImagesPerWord: 1, EnableCache: true, } } @@ -361,7 +359,7 @@ func (a *Application) generateMaterials(word string) { // Get custom prompt from UI customPrompt := a.imagePromptEntry.Text - images, err := a.generateImagesWithPrompt(word, customPrompt) + imageFile, err := a.generateImagesWithPrompt(word, customPrompt) a.decrementProcessing() // Image processing ends if err != nil { @@ -371,10 +369,12 @@ func (a *Application) generateMaterials(word string) { }) return } - a.currentImages = images - fyne.Do(func() { - a.imageDisplay.SetImages(images) - }) + if imageFile != "" { + a.currentImage = imageFile + fyne.Do(func() { + a.imageDisplay.SetImages([]string{imageFile}) + }) + } // Enable action buttons fyne.Do(func() { @@ -388,12 +388,12 @@ func (a *Application) generateMaterials(word string) { // onKeepAndContinue saves the current card and clears for a new word func (a *Application) onKeepAndContinue() { // Check if we have a complete word to save - if a.currentWord != "" && a.currentAudioFile != "" && len(a.currentImages) > 0 { + if a.currentWord != "" && a.currentAudioFile != "" && a.currentImage != "" { // Save current card card := anki.Card{ Bulgarian: a.currentWord, AudioFile: a.currentAudioFile, - ImageFiles: a.currentImages, + ImageFile: a.currentImage, Translation: a.currentTranslation, } @@ -457,16 +457,18 @@ func (a *Application) onRegenerateImage() { defer a.wg.Done() defer a.decrementProcessing() // Image processing ends - images, err := a.generateImagesWithPrompt(a.currentWord, customPrompt) + imageFile, err := a.generateImagesWithPrompt(a.currentWord, customPrompt) if err != nil { fyne.Do(func() { a.showError(fmt.Errorf("Image regeneration failed: %w", err)) }) } else { - a.currentImages = images - fyne.Do(func() { - a.imageDisplay.SetImages(images) - }) + if imageFile != "" { + a.currentImage = imageFile + fyne.Do(func() { + a.imageDisplay.SetImages([]string{imageFile}) + }) + } } fyne.Do(func() { @@ -734,7 +736,7 @@ func (a *Application) processWordJob(job *WordJob) { }) // Use the custom prompt from the job - imageFiles, err := a.generateImagesWithPrompt(job.Word, job.CustomPrompt) + imageFile, err := a.generateImagesWithPrompt(job.Word, job.CustomPrompt) a.decrementProcessing() // Image processing ends if err != nil { @@ -749,18 +751,22 @@ func (a *Application) processWordJob(job *WordJob) { a.updateStatus(fmt.Sprintf("Finalizing '%s'...", job.Word)) }) - a.queue.CompleteJob(job.ID, translation, audioFile, imageFiles) + a.queue.CompleteJob(job.ID, translation, audioFile, imageFile) // Update UI with results if this is still the current job a.mu.Lock() if a.currentJobID == job.ID { a.currentTranslation = translation a.currentAudioFile = audioFile - a.currentImages = imageFiles + if imageFile != "" { + a.currentImage = imageFile + } fyne.Do(func() { a.translationText.SetText(fmt.Sprintf("%s = %s", job.Word, translation)) - a.imageDisplay.SetImages(imageFiles) + if imageFile != "" { + a.imageDisplay.SetImages([]string{imageFile}) + } a.audioPlayer.SetAudioFile(audioFile) a.hideProgress() a.setActionButtonsEnabled(true) @@ -817,7 +823,7 @@ func (a *Application) onJobComplete(job *WordJob) { // Only update UI if the current word is still empty (waiting for this job) if job.Word == a.currentWord && job.ID != a.currentJobID { // Check if the UI is still empty/waiting for content - hasContent := a.currentAudioFile != "" || len(a.currentImages) > 0 + hasContent := a.currentAudioFile != "" || a.currentImage != "" if !hasContent { // Update the UI with the completed results since it's still waiting @@ -831,9 +837,9 @@ func (a *Application) onJobComplete(job *WordJob) { a.audioPlayer.SetAudioFile(job.AudioFile) a.regenerateAudioBtn.Enable() } - if len(job.ImageFiles) > 0 && len(a.currentImages) == 0 { - a.currentImages = job.ImageFiles - a.imageDisplay.SetImages(job.ImageFiles) + if job.ImageFile != "" && a.currentImage == "" { + a.currentImage = job.ImageFile + a.imageDisplay.SetImages([]string{job.ImageFile}) a.regenerateImageBtn.Enable() } diff --git a/internal/gui/generator.go b/internal/gui/generator.go index 9738d88..7a6d26e 100644 --- a/internal/gui/generator.go +++ b/internal/gui/generator.go @@ -86,12 +86,12 @@ func (a *Application) generateAudio(word string) (string, error) { } // generateImages downloads images for a word -func (a *Application) generateImages(word string) ([]string, error) { +func (a *Application) generateImages(word string) (string, error) { return a.generateImagesWithPrompt(word, "") } -// generateImagesWithPrompt downloads images for a word with optional custom prompt -func (a *Application) generateImagesWithPrompt(word string, customPrompt string) ([]string, error) { +// generateImagesWithPrompt downloads a single image for a word with optional custom prompt +func (a *Application) generateImagesWithPrompt(word string, customPrompt string) (string, error) { // Create image searcher based on provider var searcher image.ImageSearcher var err error @@ -102,11 +102,11 @@ func (a *Application) generateImagesWithPrompt(word string, customPrompt string) case "unsplash": if a.config.UnsplashKey == "" { - return nil, fmt.Errorf("Unsplash API key is required") + return "", fmt.Errorf("Unsplash API key is required") } searcher, err = image.NewUnsplashClient(a.config.UnsplashKey) if err != nil { - return nil, err + return "", err } case "openai": @@ -127,7 +127,7 @@ func (a *Application) generateImagesWithPrompt(word string, customPrompt string) } default: - return nil, fmt.Errorf("unknown image provider: %s", a.config.ImageProvider) + return "", fmt.Errorf("unknown image provider: %s", a.config.ImageProvider) } // Create downloader @@ -147,20 +147,10 @@ func (a *Application) generateImagesWithPrompt(word string, customPrompt string) searchOpts.CustomPrompt = customPrompt } - // Download images - var paths []string - - if a.config.ImagesPerWord == 1 { - _, path, err := downloader.DownloadBestMatchWithOptions(a.ctx, searchOpts) - if err != nil { - return nil, err - } - paths = []string{path} - } else { - paths, err = downloader.DownloadMultipleWithOptions(a.ctx, searchOpts, a.config.ImagesPerWord) - if err != nil { - return nil, err - } + // Download single image + _, path, err := downloader.DownloadBestMatchWithOptions(a.ctx, searchOpts) + if err != nil { + return "", err } // If using OpenAI, get the last used prompt and update the UI @@ -175,7 +165,7 @@ func (a *Application) generateImagesWithPrompt(word string, customPrompt string) } } - return paths, nil + return path, nil } // saveAudioAttribution saves attribution info for generated audio diff --git a/internal/gui/navigation.go b/internal/gui/navigation.go index 05bf988..bc65c8f 100644 --- a/internal/gui/navigation.go +++ b/internal/gui/navigation.go @@ -175,7 +175,7 @@ func (a *Application) loadWordByIndex(index int) { // Load from queue job a.currentTranslation = job.Translation a.currentAudioFile = job.AudioFile - a.currentImages = job.ImageFiles + a.currentImage = job.ImageFile fyne.Do(func() { if job.Translation != "" { @@ -184,8 +184,8 @@ func (a *Application) loadWordByIndex(index int) { if job.AudioFile != "" { a.audioPlayer.SetAudioFile(job.AudioFile) } - if len(job.ImageFiles) > 0 { - a.imageDisplay.SetImages(job.ImageFiles) + if job.ImageFile != "" { + a.imageDisplay.SetImages([]string{job.ImageFile}) } a.updateStatus(fmt.Sprintf("Loaded from queue: %s", word)) }) @@ -234,8 +234,8 @@ func (a *Application) loadExistingFiles(word string) { }) } - // Load image files - a.currentImages = []string{} + // Load image file + a.currentImage = "" // Try to find images with different patterns patterns := []string{ fmt.Sprintf("%s.jpg", sanitized), @@ -249,20 +249,20 @@ func (a *Application) loadExistingFiles(word string) { for _, pattern := range patterns { imagePath := filepath.Join(a.config.OutputDir, pattern) if _, err := os.Stat(imagePath); err == nil { - a.currentImages = append(a.currentImages, imagePath) + a.currentImage = imagePath break // Just load the first image found } } - if len(a.currentImages) > 0 { + if a.currentImage != "" { fyne.Do(func() { - a.imageDisplay.SetImages(a.currentImages) + a.imageDisplay.SetImages([]string{a.currentImage}) }) // Try to load the prompt from attribution file if using OpenAI - if a.config.ImageProvider == "openai" && len(a.currentImages) > 0 { + if a.config.ImageProvider == "openai" { // Look for attribution file - baseImagePath := a.currentImages[0] + baseImagePath := a.currentImage attrPath := strings.TrimSuffix(baseImagePath, filepath.Ext(baseImagePath)) + "_attribution.txt" if data, err := os.ReadFile(attrPath); err == nil { // Parse prompt from attribution file diff --git a/internal/gui/queue.go b/internal/gui/queue.go index aaa0c55..df39908 100644 --- a/internal/gui/queue.go +++ b/internal/gui/queue.go @@ -13,7 +13,7 @@ type WordJob struct { Word string Translation string AudioFile string - ImageFiles []string + ImageFile string // Changed from ImageFiles []string to single image Status JobStatus Error error StartedAt time.Time @@ -194,7 +194,7 @@ func (q *WordQueue) Stop() { } // CompleteJob marks a job as completed with results -func (q *WordQueue) CompleteJob(jobID int, translation, audioFile string, imageFiles []string) { +func (q *WordQueue) CompleteJob(jobID int, translation, audioFile, imageFile string) { q.mu.Lock() defer q.mu.Unlock() @@ -202,7 +202,7 @@ func (q *WordQueue) CompleteJob(jobID int, translation, audioFile string, imageF job.Status = StatusCompleted job.Translation = translation job.AudioFile = audioFile - job.ImageFiles = imageFiles + job.ImageFile = imageFile job.CompletedAt = time.Now() delete(q.processing, jobID) |
