func generateAudio()

in experiments/babel/speak.go [212:290]


func generateAudio(ctx context.Context, client *genai.Client, chosenVoice string, prompt string, prettyprint bool) (string, error) {
	config := &genai.GenerateContentConfig{}
	config.ResponseModalities = []string{"AUDIO"}
	config.SpeechConfig = &genai.SpeechConfig{
		VoiceConfig: &genai.VoiceConfig{
			PrebuiltVoiceConfig: &genai.PrebuiltVoiceConfig{
				VoiceName: chosenVoice,
			},
		},
	}

	/*
		result, err := client.Models.GenerateContent(ctx, model, genai.Text(prompt), config)
		if err != nil {
			log.Fatal(err)
		}
	*/

	var result *genai.GenerateContentResponse
	var err error

	maxRetries := 4
	retryCount := 0
	duration := 3 * time.Second    // Initial backoff duration
	maxDuration := 1 * time.Minute // Maximum backoff duration

	for retryCount < maxRetries {
		result, err = client.Models.GenerateContent(ctx, model, genai.Text(prompt), config)
		if err == nil {
			break // Success!
		}
		// TODO add break on 403, permission denied
		log.Print(err.Error())

		// retry logic
		retryCount++
		log.Printf("Error: %v, retrying in %v (attempt %d/%d)", err, duration, retryCount, maxRetries)
		time.Sleep(duration) // Wait for the backoff duration
		// Exponential backoff with jitter
		duration *= 2
		duration += time.Duration(rand.Int63n(int64(duration / 2))) // Add jitter
		if duration > maxDuration {
			duration = maxDuration
		}
		// TEMP try again with a random client
		client = createGeminiClient(ctx, projectID)
	}

	if err != nil {
		return "", fmt.Errorf("Failed after %d retries: %v", maxRetries, err)
	}

	if prettyprint {
		prettyPrintJSON(result)
	}

	if result.Candidates[0].FinishReason == "STOP" {
		timestamp := time.Now().Format(timeformat)
		mimeType := result.Candidates[0].Content.Parts[0].InlineData.MIMEType
		ext := getFileExtensionFromMimeType(mimeType)
		var filename string
		if outputfile == "" {
			filename = fmt.Sprintf("%s-%s%s", timestamp, chosenVoice, ext)
		} else {
			filename = outputfile
		}
		audiobytes := result.Candidates[0].Content.Parts[0].InlineData.Data
		err = os.WriteFile(filename, audiobytes, 0644)
		if err != nil {
			log.Println(err)
		}
		log.Printf("Written to %s", filename)
		return filename, nil
	} else {
		log.Printf("Finish reason: %s", result.Candidates[0].FinishReason)
	}

	return "", fmt.Errorf("finish reason: %s", result.Candidates[0].FinishReason)
}