Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions cmd/gomodel/docs/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

134 changes: 134 additions & 0 deletions docs/openapi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/auditlog/auditlog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,7 @@ func TestIsModelInteractionPath(t *testing.T) {
{"batches prefix overmatch", "/v1/batcheship", false},
{"audio speech", "/v1/audio/speech", true},
{"audio transcriptions", "/v1/audio/transcriptions", true},
{"audio translations", "/v1/audio/translations", true},
{"models", "/v1/models", false},
{"models with subpath", "/v1/models/gpt-4", false},
{"health", "/health", false},
Expand Down
9 changes: 8 additions & 1 deletion internal/core/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
OperationFiles Operation = "files"
OperationAudioSpeech Operation = "audio_speech"
OperationAudioTranscriptions Operation = "audio_transcriptions"
OperationAudioTranslations Operation = "audio_translations"
OperationRealtime Operation = "realtime"
OperationProviderPassthrough Operation = "provider_passthrough"
OperationMCP Operation = "mcp"
Expand Down Expand Up @@ -142,6 +143,12 @@ func describeEndpointPath(path string) EndpointDescriptor {
Dialect: "openai_compat",
Operation: OperationAudioTranscriptions,
}
case path == "/v1/audio/translations":
return EndpointDescriptor{
ModelInteraction: true,
Dialect: "openai_compat",
Operation: OperationAudioTranslations,
}
case path == "/v1/realtime" || path == "/v1/realtime/calls" || path == "/v1/realtime/client_secrets":
// The realtime endpoints relay the provider's schema verbatim: /v1/realtime
// upgrades to a websocket, /v1/realtime/calls exchanges WebRTC SDP, and
Expand Down Expand Up @@ -212,7 +219,7 @@ func bodyModeForEndpoint(method, path string, operation Operation) BodyMode {
return BodyModeNone
case OperationAudioSpeech:
return BodyModeJSON
case OperationAudioTranscriptions:
case OperationAudioTranscriptions, OperationAudioTranslations:
return BodyModeMultipart
case OperationRealtime:
if method == http.MethodPost && path == "/v1/realtime/client_secrets" {
Expand Down
2 changes: 2 additions & 0 deletions internal/core/endpoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestDescribeEndpointPath(t *testing.T) {
{path: "/v1/files/file_1", managed: true, dialect: "openai_compat", operation: OperationFiles, bodyMode: BodyModeNone, interaction: true},
{path: "/v1/audio/speech", managed: false, dialect: "openai_compat", operation: OperationAudioSpeech, bodyMode: BodyModeJSON, interaction: true},
{path: "/v1/audio/transcriptions", managed: false, dialect: "openai_compat", operation: OperationAudioTranscriptions, bodyMode: BodyModeMultipart, interaction: true},
{path: "/v1/audio/translations", managed: false, dialect: "openai_compat", operation: OperationAudioTranslations, bodyMode: BodyModeMultipart, interaction: true},
{path: "/mcp", managed: false, dialect: "mcp", operation: OperationMCP, bodyMode: BodyModeNone, interaction: true},
{path: "/mcp/linear", managed: false, dialect: "mcp", operation: OperationMCP, bodyMode: BodyModeNone, interaction: true},
{path: "/p/openai/responses", managed: true, dialect: "provider_passthrough", operation: OperationProviderPassthrough, bodyMode: BodyModeOpaque, interaction: true},
Expand Down Expand Up @@ -86,6 +87,7 @@ func TestDescribeEndpoint_UsesMethodForBodyMode(t *testing.T) {
{method: http.MethodGet, path: "/v1/files/file_1", bodyMode: BodyModeNone},
{method: http.MethodPost, path: "/v1/audio/speech", bodyMode: BodyModeJSON},
{method: http.MethodPost, path: "/v1/audio/transcriptions", bodyMode: BodyModeMultipart},
{method: http.MethodPost, path: "/v1/audio/translations", bodyMode: BodyModeMultipart},
{method: http.MethodPost, path: "/v1/batches/batch_1/cancel", bodyMode: BodyModeNone},
{method: http.MethodPost, path: "/mcp", bodyMode: BodyModeJSON},
{method: http.MethodGet, path: "/mcp", bodyMode: BodyModeNone},
Expand Down
8 changes: 8 additions & 0 deletions internal/core/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ type AudioProvider interface {
CreateTranscription(ctx context.Context, req *AudioTranscriptionRequest) (*AudioResponse, error)
}

// AudioTranslationProvider is implemented by audio providers that support
// translating spoken audio into English through POST /v1/audio/translations.
// It is separate from AudioProvider because transcription support does not imply
// translation support for every upstream provider.
type AudioTranslationProvider interface {
CreateTranslation(ctx context.Context, req *AudioTranscriptionRequest) (*AudioResponse, error)
}

// NativeBatchProvider is implemented by providers that support native discounted batching.
// This is intentionally separate from Provider so unsupported providers can still implement
// regular synchronous APIs without batch capabilities.
Expand Down
6 changes: 6 additions & 0 deletions internal/providers/groq/groq.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,9 @@ func (p *Provider) CreateSpeech(ctx context.Context, req *core.AudioSpeechReques
func (p *Provider) CreateTranscription(ctx context.Context, req *core.AudioTranscriptionRequest) (*core.AudioResponse, error) {
return p.compat.CreateTranscription(ctx, req)
}

// CreateTranslation translates audio through Groq's OpenAI-compatible
// /audio/translations API (whisper models).
func (p *Provider) CreateTranslation(ctx context.Context, req *core.AudioTranscriptionRequest) (*core.AudioResponse, error) {
return p.compat.CreateTranslation(ctx, req)
}
Loading