diff options
Diffstat (limited to 'internal/gui/parallel_runner.go')
| -rw-r--r-- | internal/gui/parallel_runner.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/internal/gui/parallel_runner.go b/internal/gui/parallel_runner.go new file mode 100644 index 0000000..2567304 --- /dev/null +++ b/internal/gui/parallel_runner.go @@ -0,0 +1,130 @@ +package gui + +import ( + "context" + "fmt" + "os" + "path/filepath" +) + +// GenerateResult holds the outcome of a parallel generation run. +type GenerateResult struct { + AudioFile string + AudioFileBack string + ImageFile string + PhoneticInfo string +} + +// audioGenResult is an internal channel payload for audio goroutines. +type audioGenResult struct { + file string + fileBack string + err error +} + +// imageGenResult is an internal channel payload for image goroutines. +type imageGenResult struct { + file string + err error +} + +// phoneticGenResult is an internal channel payload for phonetic goroutines. +type phoneticGenResult struct { + info string + err error +} + +// ParallelRunner coordinates parallel audio, image, and phonetics work for +// material generation. It is stateless; the orchestrator supplies all behaviour +// via the first method argument. +type ParallelRunner struct{} + +// GenerateMaterials generates audio, image, and phonetics in parallel for a +// word. translation is the existing translation (may be empty). isBgBg flags +// bg-bg card type. imagePrompt is an optional custom prompt; imageTranslation +// is the translation hint for image prompts. +// The promptUI callback is called on the generating goroutine when the image +// prompt becomes known so callers can update the UI. +// Returns a GenerateResult or an error if any mandatory step fails. +func (ParallelRunner) GenerateMaterials( + o *GenerationOrchestrator, + ctx context.Context, + word, translation, cardDir string, + isBgBg bool, + imagePrompt string, + promptUI func(prompt string), +) (GenerateResult, error) { + audioChan := make(chan audioGenResult, 1) + imageChan := make(chan imageGenResult, 1) + phoneticChan := make(chan phoneticGenResult, 1) + + // 1. Audio generation + go func() { + var audioFile, audioFileBack string + var err error + + if isBgBg && translation != "" { + audioFile, audioFileBack, err = o.GenerateAudioBgBg(ctx, word, translation, cardDir) + } else { + audioFile, err = o.GenerateAudio(ctx, word, cardDir) + } + + audioChan <- audioGenResult{file: audioFile, fileBack: audioFileBack, err: err} + }() + + // 2. Image generation (includes scene description from the AI) + go func() { + imageFile, err := o.generateImagesWithPromptAndNotify(ctx, word, imagePrompt, translation, cardDir, promptUI) + imageChan <- imageGenResult{file: imageFile, err: err} + }() + + // 3. Phonetic information fetching + go func() { + phoneticInfo, err := o.GetPhoneticInfo(word) + if err != nil { + fmt.Printf("Warning: Failed to get phonetic info: %v\n", err) + phoneticInfo = "Failed to fetch phonetic information" + } else { + fmt.Printf("Successfully fetched phonetic info for '%s': %s\n", word, phoneticInfo) + } + + savePhoneticIfValid(phoneticInfo, cardDir, word) + phoneticChan <- phoneticGenResult{info: phoneticInfo} + }() + + // Collect results. + audioRes := <-audioChan + if audioRes.err != nil { + // Drain remaining channels to avoid goroutine leaks. + <-imageChan + <-phoneticChan + return GenerateResult{}, fmt.Errorf("audio generation failed: %w", audioRes.err) + } + + imageRes := <-imageChan + if imageRes.err != nil { + <-phoneticChan + return GenerateResult{}, fmt.Errorf("image download failed: %w", imageRes.err) + } + + phoneticRes := <-phoneticChan + + return GenerateResult{ + AudioFile: audioRes.file, + AudioFileBack: audioRes.fileBack, + ImageFile: imageRes.file, + PhoneticInfo: phoneticRes.info, + }, nil +} + +// savePhoneticIfValid saves phonetic info to disk when the info is valid. +func savePhoneticIfValid(phoneticInfo, cardDir, word string) { + if phoneticInfo == "" || phoneticInfo == "Failed to fetch phonetic information" { + return + } + + phoneticFile := filepath.Join(cardDir, "phonetic.txt") + if err := os.WriteFile(phoneticFile, []byte(phoneticInfo), 0644); err != nil { + fmt.Printf("Warning: Failed to save phonetic info for '%s': %v\n", word, err) + } +} |
