Skip to content
For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Primary navigation

Connect

Open a Realtime translation session. The WebSocket URL requires a model query parameter.

WebSocket wss://api.openai.com/v1/realtime/translations

Connect

package main

import (
	"context"
	"encoding/base64"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
	"github.com/openai/openai-go/v3/realtime"
)

func main() {
	if err := translate(); err != nil {
		log.Fatal(err)
	}
}

func translate() error {
	// input.pcm: a short recording of raw 24 kHz mono signed PCM16 little-endian audio.
	pcm, err := os.ReadFile("input.pcm")
	if err != nil {
		return err
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	client := openai.NewClient()
	connection, err := client.Realtime.Translations.Connect(ctx, realtime.TranslationConnectionOptions{}, option.WithQuery("model", "gpt-realtime-translate"))
	if err != nil {
		return err
	}
	defer connection.Close()

	if err := connection.Send(ctx, realtime.RealtimeTranslationClientEventUnionParam{
		OfSessionUpdate: &realtime.RealtimeTranslationSessionUpdateEventParam{
			Session: realtime.RealtimeTranslationSessionUpdateRequestParam{
				Audio: realtime.RealtimeTranslationSessionUpdateRequestAudioParam{
					Output: realtime.RealtimeTranslationSessionUpdateRequestAudioOutputParam{Language: openai.String("es")},
				},
			},
		},
	}); err != nil {
		return err
	}
	// Wait for the language change before sending audio.
	for {
		event, err := connection.Recv(ctx)
		if err != nil {
			return fmt.Errorf("translation ended before session.updated: %w", err)
		}
		switch message := event.AsAny().(type) {
		case realtime.RealtimeErrorEvent:
			return fmt.Errorf("translation failed: %s", message.Error.Message)
		case realtime.RealtimeTranslationSessionClosedEvent:
			return fmt.Errorf("translation closed before session.updated")
		}
		if event.Type == "session.updated" {
			break
		}
	}
	for offset := 0; offset < len(pcm); offset += 9600 {
		end := min(offset+9600, len(pcm))
		if err := connection.Send(ctx, realtime.RealtimeTranslationClientEventUnionParam{
			OfSessionInputAudioBufferAppend: &realtime.RealtimeTranslationInputAudioBufferAppendEventParam{
				Audio: base64.StdEncoding.EncodeToString(pcm[offset:end]),
			},
		}); err != nil {
			return err
		}
	}
	// Close the session to flush remaining audio, then read the final translated text.
	if err := connection.Send(ctx, realtime.RealtimeTranslationClientEventUnionParam{
		OfSessionClose: &realtime.RealtimeTranslationSessionCloseEventParam{},
	}); err != nil {
		return err
	}
	for {
		event, err := connection.Recv(ctx)
		if err != nil {
			return fmt.Errorf("translation ended before session.closed: %w", err)
		}
		switch message := event.AsAny().(type) {
		case realtime.RealtimeTranslationOutputTranscriptDeltaEvent:
			fmt.Print(message.Delta)
		case realtime.RealtimeErrorEvent:
			return fmt.Errorf("translation failed: %s", message.Error.Message)
		case realtime.RealtimeTranslationSessionClosedEvent:
			return nil
		}
	}
}