Skip to content

feat(audio): add translations endpoint - #639

Merged
SantiagoDePolonia merged 4 commits into
ENTERPILOT:mainfrom
sidsri14:feat/audio-translations
Aug 4, 2026
Merged

feat(audio): add translations endpoint#639
SantiagoDePolonia merged 4 commits into
ENTERPILOT:mainfrom
sidsri14:feat/audio-translations

Conversation

@sidsri14

@sidsri14 sidsri14 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add the OpenAI-compatible POST /v1/audio/translations route and generated API docs
  • route translations through an optional provider capability implemented by OpenAI-compatible and Groq audio backends
  • reuse transcription upload, authorization, rate-limit, audit, response, and usage handling while omitting translation-unsupported language and timestamp fields
  • add provider, router, HTTP route, and usage endpoint coverage

Testing

  • go test -p 2 ./cmd/... ./config/... ./ext/... ./internal/... ./run/... (passes with ambient OLLAMA_MODELS unset)
  • go mod verify
  • generated Swagger/OpenAPI artifacts; parsed docs/openapi.json
  • git diff --check

Local limitations

  • go test -race cannot build because the installed Windows C compiler reports 64-bit mode not compiled in
  • go vet reaches pre-existing duplicate JSON-tag findings in internal/core/responses.go and internal/core/types.go
  • golangci-lint is not installed locally; GitHub CI runs the repository-pinned v2.12 action

Closes #632

Summary by CodeRabbit

  • New Features

    • Added the POST /v1/audio/translations endpoint for translating uploaded audio into English.
    • Supports multipart uploads with model selection, optional prompts, response formats, and temperature settings.
    • Added support for compatible providers, including Groq and OpenAI-compatible services.
    • Translation requests validate supported fields and provide endpoint-specific responses, errors, and usage tracking.
  • Documentation

    • Updated OpenAPI and Swagger documentation with request, response, authentication, and error details.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 44489366-aa39-4d01-b4bf-995714353703

📥 Commits

Reviewing files that changed from the base of the PR and between a3aae24 and 7911b9d.

📒 Files selected for processing (2)
  • internal/server/audio_service.go
  • internal/server/audio_service_test.go

📝 Walkthrough

Walkthrough

Added POST /v1/audio/translations with multipart parsing, provider routing, OpenAI-compatible requests, response handling, usage tracking, tests, and generated API documentation.

Changes

Audio translations

Layer / File(s) Summary
Endpoint contract and classification
internal/core/endpoints.go, internal/core/endpoints_test.go, internal/server/http.go, internal/server/handlers.go, cmd/gomodel/docs/docs.go, docs/openapi.json
Added endpoint classification, route registration, handler delegation, and OpenAPI documentation for multipart translation requests and responses.
Provider translation capability
internal/core/interfaces.go, internal/providers/openai/audio.go, internal/providers/groq/groq.go, internal/providers/openai/audio_test.go
Added translation provider methods. Generalized multipart requests and excluded transcription-only fields from translation requests.
Routing and service dispatch
internal/providers/router.go, internal/providers/router_test.go, internal/server/audio_service.go, internal/server/audio_service_test.go
Added capability checks, provider routing, shared request parsing, translation dispatch, validation, and service tests.
Usage tracking and regression coverage
internal/usage/audio.go, internal/usage/audio_test.go, internal/auditlog/auditlog_test.go, internal/server/http_start_test.go
Added translation usage extraction and endpoint-specific cost tracking. Extended endpoint, audit-log, middleware, and usage tests.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AudioTranslations as handler.AudioTranslations
  participant audioService
  participant Router
  participant AudioTranslationProvider
  Client->>AudioTranslations: POST multipart translation request
  AudioTranslations->>audioService: CreateTranslation
  audioService->>Router: CreateTranslation with parsed request
  Router->>AudioTranslationProvider: CreateTranslation
  AudioTranslationProvider-->>Router: AudioResponse
  Router-->>audioService: AudioResponse
  audioService-->>AudioTranslations: Translation response
Loading

Possibly related PRs

Suggested reviewers: santiagodepolonia

Poem

A rabbit sends an audio file,
The translation route runs in style.
Providers carry fields downstream,
English text returns sound and calm.
Usage records hop in place.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: adding the audio translations endpoint.
Description check ✅ Passed The description explains the implementation, testing, generated artifacts, limitations, and linked issue, despite using Summary instead of Description.
Linked Issues check ✅ Passed The changes implement /v1/audio/translations with multipart uploads, English translation behavior, field validation, provider support, reuse, and coverage required by [#632].
Out of Scope Changes check ✅ Passed The changes remain focused on the translation endpoint, related provider plumbing, documentation, classification, usage handling, middleware coverage, and tests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sidsri14
sidsri14 marked this pull request as ready for review August 3, 2026 12:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/server/audio_service.go (1)

269-301: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject transcription-only fields on translation requests.

The translation parser silently ignores language and timestamp_granularities. The endpoint contract requires these fields to be unsupported, not discarded. Return an invalid-request error when either field is present.

  • internal/server/audio_service.go#L269-L301: Detect language, timestamp_granularities, and timestamp_granularities[] for translations and reject the request.
  • internal/server/audio_service_test.go#L253-L280: Split valid and invalid requests. Assert a 400 response when a translation request includes unsupported fields.

Based on PR objectives, /v1/audio/translations must not accept a language input parameter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/server/audio_service.go` around lines 269 - 301, Update
audioTranscriptionRequestFromForm in internal/server/audio_service.go lines
269-301 to reject translation requests when language, timestamp_granularities,
or timestamp_granularities[] is present, returning an invalid-request error
instead of ignoring the fields; retain existing parsing for transcription
requests. Update internal/server/audio_service_test.go lines 253-280 to separate
valid and invalid translation cases and assert a 400 response for each
unsupported field.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/providers/openai/audio_test.go`:
- Around line 68-126: Extend the audio provider tests with negative cases for
CreateTranslation: verify a nil request returns “audio translation request is
required,” and a request with neither File nor FileReader returns “file is
required.” Prefer a table-driven test near
TestCreateTranslation_UsesTranslationMultipartShape, preserving the existing
translation-shape assertions.

In `@internal/providers/router_test.go`:
- Around line 384-420: Convert the affected tests to table-driven coverage: in
internal/providers/router_test.go lines 384-420, extend
TestRouterCreateTranslation with provider-failure and invalid-translation-input
cases, verifying CreateTranslation propagates configured provider errors; in
internal/server/audio_service_test.go lines 243-284, add invalid-field and
provider-error cases and assert each HTTP status and error envelope; in
internal/usage/audio_test.go lines 103-108, use a table covering both
transcription and translation endpoint attribution.

---

Outside diff comments:
In `@internal/server/audio_service.go`:
- Around line 269-301: Update audioTranscriptionRequestFromForm in
internal/server/audio_service.go lines 269-301 to reject translation requests
when language, timestamp_granularities, or timestamp_granularities[] is present,
returning an invalid-request error instead of ignoring the fields; retain
existing parsing for transcription requests. Update
internal/server/audio_service_test.go lines 253-280 to separate valid and
invalid translation cases and assert a 400 response for each unsupported field.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 64e530b2-b284-44f8-88a6-65a6ee68f7f7

📥 Commits

Reviewing files that changed from the base of the PR and between 9d54827 and a3f36be.

📒 Files selected for processing (14)
  • cmd/gomodel/docs/docs.go
  • docs/openapi.json
  • internal/core/interfaces.go
  • internal/providers/groq/groq.go
  • internal/providers/openai/audio.go
  • internal/providers/openai/audio_test.go
  • internal/providers/router.go
  • internal/providers/router_test.go
  • internal/server/audio_service.go
  • internal/server/audio_service_test.go
  • internal/server/handlers.go
  • internal/server/http.go
  • internal/usage/audio.go
  • internal/usage/audio_test.go

Comment thread internal/providers/openai/audio_test.go
Comment thread internal/providers/router_test.go
@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR is safe to merge; no blocking failure remains.

Focused execution confirmed the configured multipart-memory behavior and preserved normal transcription success and invalid-request handling.

T-Rex T-Rex Logs

What T-Rex did

  • A focused low-memory multipart repro against the parent commit was executed and showed the uploaded file opened as in-memory multipart.sectionReadCloser.
  • The added multipart-memory regression test and the exact /v1/audio/transcriptions handler test were run, and the upload opened as *os.File with the model fields and audio bytes preserved, the request succeeded, and the missing-file path returned 400.
  • These results demonstrate that the revised parsing order honors the configured memory limit without changing the endpoint’s normal request behavior.
  • Before: the parent commit parsed the upload as in-memory; After: the added regression test and the exact /v1/audio/transcriptions handler test pass with the file stored as *os.File and malformed missing-file input still returns 400.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "fix(audio): honor multipart memory limit" | Re-trigger Greptile

@sidsri14

sidsri14 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the model-interaction classification finding in 7310a4e. /v1/audio/translations now has its own multipart endpoint descriptor with ModelInteraction: true; endpoint/audit classification and write-deadline middleware tests cover the route. The same commit rejects transcription-only form fields and adds provider/router/server negative-path coverage. Focused regressions and the complete six affected package suites pass.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/server/audio_service.go (1)

269-327: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Validate disallowed fields before reading the uploaded file into memory.

audioTranscriptionRequestFromForm reads the entire file body with io.ReadAll (lines 279-287) before it calls c.MultipartForm() and rejects translation requests that carry language or timestamp_granularities fields (lines 289-299). A translation request that is going to be rejected for an unsupported field still pays the full cost of reading the uploaded audio into memory.

Move the c.MultipartForm() call and the disallowed-field check ahead of the file open/read, so invalid translation requests fail before the file body is buffered.

♻️ Proposed reordering
 func audioTranscriptionRequestFromForm(c *echo.Context, includeTranscriptionFields bool) (*core.AudioTranscriptionRequest, error) {
 	model := strings.TrimSpace(c.FormValue("model"))
 	if model == "" {
 		return nil, core.NewInvalidRequestError("model is required", nil)
 	}
 
+	form, err := c.MultipartForm()
+	if err != nil {
+		return nil, core.NewInvalidRequestError("invalid multipart form", err)
+	}
+	if !includeTranscriptionFields && form != nil {
+		for _, field := range []string{"language", "timestamp_granularities", "timestamp_granularities[]"} {
+			if _, present := form.Value[field]; present {
+				return nil, core.NewInvalidRequestError(field+" is not supported for audio translations", nil)
+			}
+		}
+	}
+
 	fileHeader, err := c.FormFile("file")
 	if err != nil {
 		return nil, core.NewInvalidRequestError("file is required", err)
 	}
 	file, err := fileHeader.Open()
 	if err != nil {
 		return nil, core.NewInvalidRequestError("failed to open uploaded file", err)
 	}
 	defer func() { _ = file.Close() }()
 	data, err := io.ReadAll(file)
 	if err != nil {
 		return nil, core.NewInvalidRequestError("failed to read uploaded file", err)
 	}
-
-	form, err := c.MultipartForm()
-	if err != nil {
-		return nil, core.NewInvalidRequestError("invalid multipart form", err)
-	}
-	if !includeTranscriptionFields && form != nil {
-		for _, field := range []string{"language", "timestamp_granularities", "timestamp_granularities[]"} {
-			if _, present := form.Value[field]; present {
-				return nil, core.NewInvalidRequestError(field+" is not supported for audio translations", nil)
-			}
-		}
-	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/server/audio_service.go` around lines 269 - 327, Update
audioTranscriptionRequestFromForm so c.MultipartForm() and the
includeTranscriptionFields disallowed-field validation occur immediately after
validating the model and before opening or reading the uploaded file. Preserve
the existing invalid multipart-form and unsupported-field errors, then perform
fileHeader.Open and io.ReadAll only after validation passes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/server/audio_service.go`:
- Around line 269-327: Update audioTranscriptionRequestFromForm so
c.MultipartForm() and the includeTranscriptionFields disallowed-field validation
occur immediately after validating the model and before opening or reading the
uploaded file. Preserve the existing invalid multipart-form and
unsupported-field errors, then perform fileHeader.Open and io.ReadAll only after
validation passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 758b6319-f644-4a20-b2f1-51ae371e878c

📥 Commits

Reviewing files that changed from the base of the PR and between a3f36be and 7310a4e.

📒 Files selected for processing (10)
  • internal/auditlog/auditlog_test.go
  • internal/core/endpoints.go
  • internal/core/endpoints_test.go
  • internal/providers/openai/audio_test.go
  • internal/providers/router.go
  • internal/providers/router_test.go
  • internal/server/audio_service.go
  • internal/server/audio_service_test.go
  • internal/server/http_start_test.go
  • internal/usage/audio_test.go

@sidsri14

sidsri14 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the latest outside-diff review in a3aae24 by moving multipart unsupported-field validation before FormFile and io.ReadAll, so rejected translation requests do not buffer the uploaded audio. TestAudioTranslation_ErrorResponses and the complete internal/server package both pass.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/server/audio_service.go`:
- Around line 275-285: Update the multipart parsing flow in the surrounding
audio request handler to call c.MultipartForm() before the first
c.FormValue("model") access, allowing Echo’s configured FormParseMaxMemory to
apply. Preserve the existing invalid-form error handling, then read model from
the already parsed request instead of triggering http.Request.FormValue parsing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 58be71b8-672b-4172-b9b4-6c36fd11b78a

📥 Commits

Reviewing files that changed from the base of the PR and between 7310a4e and a3aae24.

📒 Files selected for processing (1)
  • internal/server/audio_service.go

Comment thread internal/server/audio_service.go Outdated
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 76.59574% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/providers/openai/audio.go 56.52% 8 Missing and 2 partials ⚠️
internal/server/audio_service.go 75.00% 5 Missing and 5 partials ⚠️
internal/providers/groq/groq.go 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@SantiagoDePolonia
SantiagoDePolonia self-requested a review August 4, 2026 13:41

@SantiagoDePolonia SantiagoDePolonia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, tested locally

@SantiagoDePolonia
SantiagoDePolonia merged commit 82d8213 into ENTERPILOT:main Aug 4, 2026
14 checks passed
@SantiagoDePolonia

Copy link
Copy Markdown
Contributor

@sidsri14 Thank you for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add /v1/audio/translations endpoint

3 participants